blob: bf38fc19b8b37c797347ea70d6c87460562da19f [file] [edit]
/*
* Copyright (c) 2025-2026 The Khronos Group Inc.
* Copyright (C) 2025 Arm Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include "layer_validation_tests.h"
#include "pipeline_helper.h"
#include "descriptor_helper.h"
#include "data_graph_objects.h"
#include "generated/pnext_chain_extraction.h"
#include "layers/utils/vk_struct_compare.h"
#include <vector>
class NegativeDataGraph : public DataGraphTest {};
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesFeatureNotEnabled) {
TEST_DESCRIPTION("Try to create a DataGraphPipeline when the dataGraph feature is not enabled");
// add all the requirements of InitBasicDataGraph except dataGraph
SetTargetApiVersion(VK_API_VERSION_1_4);
AddRequiredExtensions(VK_ARM_TENSORS_EXTENSION_NAME);
AddRequiredExtensions(VK_ARM_DATA_GRAPH_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::tensors);
AddRequiredFeature(vkt::Feature::dataGraphShaderModule);
AddRequiredFeature(vkt::Feature::shaderTensorAccess);
AddRequiredFeature(vkt::Feature::vulkanMemoryModel);
AddRequiredFeature(vkt::Feature::shaderInt8);
RETURN_IF_SKIP(Init());
// this error is generated by the spirv verification, which runs already in the constructor
m_errorMonitor->SetAllowedFailureMsg("VUID-VkShaderModuleCreateInfo-pCode-08740");
vkt::dg::DataGraphPipelineHelper pipeline(*this);
m_errorMonitor->SetDesiredError("VUID-vkCreateDataGraphPipelinesARM-dataGraph-09760");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesDeferredOperationNotNull) {
TEST_DESCRIPTION("Try to create a DataGraphPipeline when deferredOperation is not VK_NULL_HANDLE");
AddRequiredExtensions(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline_helper(*this);
VkDeferredOperationKHR deferred_operation;
vk::CreateDeferredOperationKHR(*m_device, nullptr, &deferred_operation);
VkPipeline pipeline;
m_errorMonitor->SetDesiredError("VUID-vkCreateDataGraphPipelinesARM-deferredOperation-09761");
vk::CreateDataGraphPipelinesARM(*m_device, deferred_operation, VK_NULL_HANDLE, 1, &pipeline_helper.pipeline_ci_, nullptr,
&pipeline);
m_errorMonitor->VerifyFound();
vk::DestroyDeferredOperationKHR(*m_device, deferred_operation, nullptr);
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesDeferredOperationWrongFlags) {
TEST_DESCRIPTION("Try to create a DataGraphPipeline with deferredOperation and invalid pipeline flags");
AddRequiredExtensions(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline_helper(*this);
VkDeferredOperationKHR deferred_operation;
vk::CreateDeferredOperationKHR(*m_device, nullptr, &deferred_operation);
VkPipeline pipeline;
// set the wrong flags in the pipeline create info
pipeline_helper.pipeline_ci_.flags |= VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT;
m_errorMonitor->SetDesiredError("VUID-vkCreateDataGraphPipelinesARM-deferredOperation-09916");
// this is also triggered because deferredOperations currently MUST be NULL
m_errorMonitor->SetDesiredError("VUID-vkCreateDataGraphPipelinesARM-deferredOperation-09761");
vk::CreateDataGraphPipelinesARM(*m_device, deferred_operation, VK_NULL_HANDLE, 1, &pipeline_helper.pipeline_ci_, nullptr,
&pipeline);
m_errorMonitor->VerifyFound();
vk::DestroyDeferredOperationKHR(*m_device, deferred_operation, nullptr);
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesInvalidFlags) {
TEST_DESCRIPTION("Try to create a DataGraphPipeline with invalid flags in create_info");
RETURN_IF_SKIP(InitBasicDataGraph());
auto set_info = [](vkt::dg::DataGraphPipelineHelper& pipeline) {
pipeline.pipeline_ci_.flags = VK_PIPELINE_CREATE_2_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR;
};
vkt::dg::DataGraphPipelineHelper::OneshotTest(*this, set_info, 0, "VUID-VkDataGraphPipelineCreateInfoARM-flags-09764");
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesNoProtectedAccessButFeatureNotEnabled) {
TEST_DESCRIPTION(
"Try to create a DataGraphPipeline where flags include VK_PIPELINE_CREATE_2_NO_PROTECTED_ACCESS_BIT_EXT but "
"pipelineProtectedAccess is not enabled");
RETURN_IF_SKIP(InitBasicDataGraph());
auto set_info = [](vkt::dg::DataGraphPipelineHelper& pipeline) {
pipeline.pipeline_ci_.flags = VK_PIPELINE_CREATE_2_NO_PROTECTED_ACCESS_BIT_EXT;
};
vkt::dg::DataGraphPipelineHelper::OneshotTest(*this, set_info, 0,
"VUID-VkDataGraphPipelineCreateInfoARM-pipelineProtectedAccess-09772");
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesProtectedAccessOnlyButFeatureNotEnabled) {
TEST_DESCRIPTION(
"Try to create a DataGraphPipeline where flags include VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT_EXT but "
"pipelineProtectedAccess is not enabled");
RETURN_IF_SKIP(InitBasicDataGraph());
auto set_info = [](vkt::dg::DataGraphPipelineHelper& pipeline) {
pipeline.pipeline_ci_.flags = VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT_EXT;
};
vkt::dg::DataGraphPipelineHelper::OneshotTest(*this, set_info, 0,
"VUID-VkDataGraphPipelineCreateInfoARM-pipelineProtectedAccess-09772");
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesBothProtectedAccessBits) {
TEST_DESCRIPTION(
"Try to create a DataGraphPipeline where flags include both VK_PIPELINE_CREATE_2_NO_PROTECTED_ACCESS_BIT_EXT and "
"VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT_EXT");
AddRequiredExtensions(VK_EXT_PIPELINE_PROTECTED_ACCESS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::pipelineProtectedAccess);
RETURN_IF_SKIP(InitBasicDataGraph());
auto set_info = [](vkt::dg::DataGraphPipelineHelper& pipeline) {
pipeline.pipeline_ci_.flags =
VK_PIPELINE_CREATE_2_NO_PROTECTED_ACCESS_BIT_EXT | VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT_EXT;
};
vkt::dg::DataGraphPipelineHelper::OneshotTest(*this, set_info, 0, "VUID-VkDataGraphPipelineCreateInfoARM-flags-09773");
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesStageCreationFeedbackCountNotZero) {
TEST_DESCRIPTION(
"Try to create a DataGraphPipeline where pNext contains a VkPipelineCreationFeedbackCreateInfo structure but the "
"pipelineStageCreationFeedbackCount is not 0");
RETURN_IF_SKIP(InitBasicDataGraph());
VkPipelineCreationFeedback creation_feedback;
VkPipelineCreationFeedbackCreateInfo creation_feedback_create_info = vku::InitStructHelper();
creation_feedback_create_info.pPipelineCreationFeedback = &creation_feedback;
creation_feedback_create_info.pipelineStageCreationFeedbackCount = 1;
creation_feedback_create_info.pPipelineStageCreationFeedbacks = &creation_feedback;
auto set_info = [&](vkt::dg::DataGraphPipelineHelper& pipeline) {
pipeline.shader_module_ci_.pNext = &creation_feedback_create_info;
};
vkt::dg::DataGraphPipelineHelper::OneshotTest(*this, set_info, 0, "VUID-VkDataGraphPipelineCreateInfoARM-pNext-09804");
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesPushConstantCountNotZero) {
TEST_DESCRIPTION(
"Try to create a DataGraphPipeline where the layout was created with a non-zero pushConstantRangeCount and non-NULL "
"pushConstRange");
RETURN_IF_SKIP(InitBasicDataGraph());
std::vector<VkPushConstantRange> pcr = {{VK_SHADER_STAGE_ALL, 0, sizeof(uint32_t)}};
auto set_info = [&](vkt::dg::DataGraphPipelineHelper& pipeline) { pipeline.CreatePipelineLayout(pcr); };
vkt::dg::DataGraphPipelineHelper::OneshotTest(*this, set_info, 0, "VUID-VkDataGraphPipelineCreateInfoARM-layout-09767");
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesUpdateAfterBindFeatureNotEnabled) {
TEST_DESCRIPTION(
"Try to create a DataGraphPipeline where the descriptorSetLayout used sets the BIND_AFTER_USE_BIT but the "
"dataGraphUpdateAfterBind is not enabled");
RETURN_IF_SKIP(InitBasicDataGraph());
auto set_info = [&](vkt::dg::DataGraphPipelineHelper& pipeline) {
pipeline.descriptor_set_.reset(new OneOffDescriptorSet(pipeline.device_, pipeline.descriptor_set_layout_bindings_,
VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, nullptr,
VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT));
pipeline.CreatePipelineLayout();
};
vkt::dg::DataGraphPipelineHelper::OneshotTest(*this, set_info, 0,
"VUID-VkDataGraphPipelineCreateInfoARM-dataGraphUpdateAfterBind-09768");
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesMutableDescriptor) {
TEST_DESCRIPTION("Try to create a DataGraphPipeline with a MUTABLE descriptor (not allowed in datagraph)");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(InitBasicDataGraph());
VkDescriptorType types[] = {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE};
VkMutableDescriptorTypeListEXT mutable_descriptor_type_list = {1, types};
VkMutableDescriptorTypeCreateInfoEXT mutable_descriptor_info = vku::InitStructHelper();
mutable_descriptor_info.mutableDescriptorTypeListCount = 1;
mutable_descriptor_info.pMutableDescriptorTypeLists = &mutable_descriptor_type_list;
auto set_info = [&](vkt::dg::DataGraphPipelineHelper& pipeline) {
pipeline.descriptor_set_layout_bindings_[0].descriptorType =
VK_DESCRIPTOR_TYPE_MUTABLE_EXT; // the pipeline sets this to tensor
pipeline.descriptor_set_.reset(
new OneOffDescriptorSet(pipeline.device_, pipeline.descriptor_set_layout_bindings_, 0, &mutable_descriptor_info));
pipeline.CreatePipelineLayout();
};
vkt::dg::DataGraphPipelineHelper::OneshotTest(*this, set_info, 0, "VUID-VkDataGraphPipelineCreateInfoARM-pSetLayouts-09770");
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesEarlyReturnFlagCacheControlNotEnabled) {
TEST_DESCRIPTION(
"Try to create a DataGraphPipeline when flags contains VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT_KHR but the "
"pipelineCreationCacheControl feature is not enabled");
RETURN_IF_SKIP(InitBasicDataGraph());
auto set_info = [](vkt::dg::DataGraphPipelineHelper& pipeline) {
pipeline.pipeline_ci_.flags = VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT_KHR;
};
vkt::dg::DataGraphPipelineHelper::OneshotTest(*this, set_info, 0,
"VUID-VkDataGraphPipelineCreateInfoARM-pipelineCreationCacheControl-09871");
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesFailOnPipelineCompileFlagCacheControlNotEnabled) {
TEST_DESCRIPTION(
"Try to create a DataGraphPipeline when flags contains VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_KHR but "
"the pipelineCreationCacheControl feature is not enabled");
RETURN_IF_SKIP(InitBasicDataGraph());
auto set_info = [](vkt::dg::DataGraphPipelineHelper& pipeline) {
pipeline.pipeline_ci_.flags = VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_KHR;
};
vkt::dg::DataGraphPipelineHelper::OneshotTest(*this, set_info, 0,
"VUID-VkDataGraphPipelineCreateInfoARM-pipelineCreationCacheControl-09871");
}
TEST_F(NegativeDataGraph, CreateDataGraphPipelinesTypeMismatch) {
TEST_DESCRIPTION(
"Try to create a DataGraphPipeline where the descriptor slot in layout does not match the resource item used in the Shader "
"Module");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::HelperParameters params;
params.desc_type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; // should be tensor
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
// 2 tensors, 2 errors
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-layout-09769");
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-layout-09769");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
static void InitDefaultComputePipeline(CreateComputePipelineHelper& pipeline, VkRenderFramework* framework) {
std::vector<VkDescriptorSetLayoutBinding> bindings = {
{0, VK_DESCRIPTOR_TYPE_TENSOR_ARM, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}};
pipeline.cs_ = VkShaderObj::CreateFromGLSL(framework, kMinimalTensorGlsl, VK_SHADER_STAGE_COMPUTE_BIT);
pipeline.dsl_bindings_.resize(bindings.size());
memcpy(pipeline.dsl_bindings_.data(), bindings.data(), bindings.size() * sizeof(VkDescriptorSetLayoutBinding));
pipeline.CreateComputePipeline();
}
TEST_F(NegativeDataGraph, GetDataGraphPipelinePropertiesPipelineNotCreatedWithCreateDataGraphPipeline) {
TEST_DESCRIPTION(
"Try to get the datagraph pipeline properties for a pipeline not created with vkCreateDataGraphPipelinesARM (i.e. created "
"with vkCreateComputePipeline)");
RETURN_IF_SKIP(InitBasicDataGraph());
CreateComputePipelineHelper pipeline(*m_device);
InitDefaultComputePipeline(pipeline, this);
VkDataGraphPipelineInfoARM pipeline_info = vku::InitStructHelper();
pipeline_info.dataGraphPipeline = pipeline;
// query with `pData` null, to get back the required `dataSize`. Enough to trigger the VUID
VkDataGraphPipelinePropertyQueryResultARM query_result;
query_result = vku::InitStructHelper();
query_result.property = VK_DATA_GRAPH_PIPELINE_PROPERTY_CREATION_LOG_ARM;
query_result.pData = nullptr;
query_result.dataSize = 0;
uint32_t prop_count = 1;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineInfoARM-dataGraphPipeline-09803");
vk::GetDataGraphPipelinePropertiesARM(m_device->handle(), &pipeline_info, prop_count, &query_result);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, GetDataGraphPipelinePropertiesDuplicatedProperty) {
TEST_DESCRIPTION("Duplicate property in datagraph pipeline properties request");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
// query with `pData` null, to get back the required `dataSize`. Enough to trigger the VUID
VkDataGraphPipelineInfoARM pipeline_info = vku::InitStructHelper();
pipeline_info.dataGraphPipeline = pipeline;
std::array<VkDataGraphPipelinePropertyQueryResultARM, 3> query_results;
// properties 0 and 2 are the same: error
query_results[0] = vku::InitStructHelper();
query_results[0].property = VK_DATA_GRAPH_PIPELINE_PROPERTY_CREATION_LOG_ARM;
query_results[0].pData = nullptr;
query_results[0].dataSize = 0;
query_results[1] = vku::InitStructHelper();
query_results[1].property = VK_DATA_GRAPH_PIPELINE_PROPERTY_IDENTIFIER_ARM;
query_results[1].pData = nullptr;
query_results[1].dataSize = 0;
query_results[2] = vku::InitStructHelper();
query_results[2].property = VK_DATA_GRAPH_PIPELINE_PROPERTY_CREATION_LOG_ARM;
query_results[2].pData = nullptr;
query_results[2].dataSize = 0;
m_errorMonitor->SetDesiredError("VUID-vkGetDataGraphPipelinePropertiesARM-pProperties-09889");
vk::GetDataGraphPipelinePropertiesARM(m_device->handle(), &pipeline_info, query_results.size(), query_results.data());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, SessionCreateInfoInvalidGraphPipeline) {
TEST_DESCRIPTION(
"Try to create a DataGraphPipelineSession where the dataGraphPipeline member of VkDataGraphPipelineSessionCreateInfoARM "
"was "
"not created by vkCreateDataGraphPipelinesARM");
RETURN_IF_SKIP(InitBasicDataGraph());
CreateComputePipelineHelper pipeline(*m_device);
InitDefaultComputePipeline(pipeline, this);
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
VkDataGraphPipelineSessionARM session;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineSessionCreateInfoARM-dataGraphPipeline-09781");
vk::CreateDataGraphPipelineSessionARM(*m_device, &session_ci, nullptr, &session);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, SessionCreateInfoProtectedMemoryFeatureNotEnabled) {
TEST_DESCRIPTION(
"Try to create a DataGraphPipelineSession where the flags member of VkDataGraphPipelineSessionCreateInfoARM contains "
"VK_DATA_GRAPH_PIPELINE_SESSION_CREATE_PROTECTED_BIT_ARM but the protectedMemory feature is not enabled");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
session_ci.flags = VK_DATA_GRAPH_PIPELINE_SESSION_CREATE_PROTECTED_BIT_ARM;
VkDataGraphPipelineSessionARM session;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineSessionCreateInfoARM-protectedMemory-09782");
vk::CreateDataGraphPipelineSessionARM(*m_device, &session_ci, nullptr, &session);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, SessionGetMemoryRequirementsBindPointNotGottenPrior) {
TEST_DESCRIPTION(
"Try to get the memory requirements for a session without a prior call to "
"vkGetDataGraphPipelineSessionBindPointRequirementsARM");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci, vkt::no_mem);
VkDataGraphPipelineSessionMemoryRequirementsInfoARM session_mem_reqs = vku::InitStructHelper();
session_mem_reqs.session = session;
session_mem_reqs.bindPoint = VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_TRANSIENT_ARM;
VkMemoryRequirements2 mem_reqs = vku::InitStructHelper();
m_errorMonitor->SetDesiredError("VUID-vkGetDataGraphPipelineSessionMemoryRequirementsARM-bindPoint-09784");
vk::GetDataGraphPipelineSessionMemoryRequirementsARM(*m_device, &session_mem_reqs, &mem_reqs);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, BindSessionTwice) {
TEST_DESCRIPTION("Try to create a bind DataGraphPipelineSession on the same bindpoint twice");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
session.AllocSessionMem(device_mem);
auto session_bind_infos = InitSessionBindInfo(session, device_mem);
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
// bind again to trigger error
m_errorMonitor->SetDesiredError("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-session-09785");
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, BindSessionMemoryOffsetLargerThanSize) {
TEST_DESCRIPTION(
"Try to create a bind DataGraphPipelineSession to DeviceMemory at an offset which is larger than the allocated memory "
"size");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
session.AllocSessionMem(device_mem);
auto session_bind_infos = InitSessionBindInfo(session, device_mem);
auto& mem_req = session.MemReqs()[0];
session_bind_infos[0].memoryOffset = mem_req.memoryRequirements.size + 2 * mem_req.memoryRequirements.alignment;
m_errorMonitor->SetDesiredError("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-memoryOffset-09787");
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, BindSessionMemoryInvalidMemoryBits) {
TEST_DESCRIPTION(
"Try to create a bind DataGraphPipelineSession on a memory type who's memoryTypeBits is incompatible with the required "
"bits");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
auto& bind_point_reqs = session.BindPointReqs();
auto& mem_reqs = session.MemReqs();
for (uint32_t i = 0; i < bind_point_reqs.size(); i++) {
if (bind_point_reqs[i].bindPointType != VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_TYPE_MEMORY_ARM) {
continue;
}
VkMemoryAllocateInfo session_alloc_info = vku::InitStructHelper();
session_alloc_info.allocationSize = mem_reqs[i].memoryRequirements.size;
if (!m_device->Physical().SetMemoryType(~mem_reqs[i].memoryRequirements.memoryTypeBits, &session_alloc_info, 0)) {
GTEST_SKIP() << "Memory type not found";
}
device_mem[i] = vkt::DeviceMemory(*m_device, session_alloc_info);
}
auto session_bind_infos = InitSessionBindInfo(session, device_mem);
m_errorMonitor->SetDesiredError("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-memory-09788");
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, BindSessionMemoryInvalidOffsetAlignment) {
TEST_DESCRIPTION(
"Try to create a bind DataGraphPipelineSession at an offset which is not an integer multiple of the required alignment");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
session.AllocSessionMem(device_mem, false, 2);
auto session_bind_infos = InitSessionBindInfo(session, device_mem);
auto& mem_reqs = session.MemReqs();
session_bind_infos[0].memoryOffset = mem_reqs[0].memoryRequirements.alignment - 1;
m_errorMonitor->SetDesiredError("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-memoryOffset-09789");
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, BindSessionMemoryTooSmall) {
TEST_DESCRIPTION("Try to create a bind DataGraphPipelineSession to device memory which is too small");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
session.AllocSessionMem(device_mem, false, 1, -1);
auto session_bind_infos = InitSessionBindInfo(session, device_mem);
m_errorMonitor->SetDesiredError("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-size-09790");
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, BindProtectedSessionToUnprotectedMemory) {
TEST_DESCRIPTION("Try to bind a protected DataGraphPipelineSession to unprotected memory");
AddRequiredFeature(vkt::Feature::protectedMemory);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.flags = VK_DATA_GRAPH_PIPELINE_SESSION_CREATE_PROTECTED_BIT_ARM;
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
// allocate unprotected memory
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
auto& mem_reqs = session.MemReqs();
for (uint32_t i = 0; i < mem_reqs.size(); i++) {
VkMemoryAllocateInfo session_alloc_info = vku::InitStructHelper();
session_alloc_info.allocationSize = mem_reqs[i].memoryRequirements.size;
auto memoryTypeBits = mem_reqs[i].memoryRequirements.memoryTypeBits;
if (!m_device->Physical().SetMemoryType(memoryTypeBits, &session_alloc_info, 0, VK_MEMORY_PROPERTY_PROTECTED_BIT)) {
GTEST_SKIP() << "Memory type not found";
}
device_mem[i] = vkt::DeviceMemory(*m_device, session_alloc_info);
}
auto session_bind_infos = InitSessionBindInfo(session, device_mem);
m_errorMonitor->SetDesiredError("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-session-09791");
// we are using a different memory type from the session, which also causes an error with memoryBits
m_errorMonitor->SetAllowedFailureMsg("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-memory-09788");
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, BindUnprotectedSessionToProtectedMemory) {
TEST_DESCRIPTION("Try to bind an unprotected DataGraphPipelineSession to protected memory");
AddRequiredFeature(vkt::Feature::protectedMemory);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
// allocate protected memory
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
auto& mem_reqs = session.MemReqs();
for (uint32_t i = 0; i < mem_reqs.size(); i++) {
VkMemoryAllocateInfo session_alloc_info = vku::InitStructHelper();
session_alloc_info.allocationSize = mem_reqs[i].memoryRequirements.size;
auto memoryTypeBits = mem_reqs[i].memoryRequirements.memoryTypeBits;
if (!m_device->Physical().SetMemoryType(memoryTypeBits, &session_alloc_info, VK_MEMORY_PROPERTY_PROTECTED_BIT)) {
GTEST_SKIP() << "Memory type not found";
}
device_mem[i] = vkt::DeviceMemory(*m_device, session_alloc_info);
}
auto session_bind_infos = InitSessionBindInfo(session, device_mem);
m_errorMonitor->SetDesiredError("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-session-09792");
// we are using a different memory type from the session, which also causes an error with memoryBits
m_errorMonitor->SetAllowedFailureMsg("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-memory-09788");
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, BindSessionObjectIndexTooLarge) {
TEST_DESCRIPTION(
"Try to bind a DataGraphPipelineSession when the resource index is larger than the numObjects for the bindPoint");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
session.AllocSessionMem(device_mem);
auto session_bind_infos = InitSessionBindInfo(session, device_mem);
session_bind_infos[0].objectIndex = session.BindPointReqs()[0].numObjects + 1;
m_errorMonitor->SetDesiredError("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-objectIndex-09805");
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, BindSessionObjectWrongBindPoint) {
TEST_DESCRIPTION("Try to bind a DataGraphPipelineSession with the wrong bindpoint");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
session.AllocSessionMem(device_mem);
auto session_bind_infos = InitSessionBindInfo(session, device_mem);
session_bind_infos[0].bindPoint =
static_cast<VkDataGraphPipelineSessionBindPointARM>(VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_MAX_ENUM_ARM - 1);
m_errorMonitor->SetDesiredError("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-bindPoint-09786");
// VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_TRANSIENT_ARM is the only legal value for bindPoint, so whatever we
// put in place of it, we also trigger this implicit check:
m_errorMonitor->SetAllowedFailureMsg("VUID-VkBindDataGraphPipelineSessionMemoryInfoARM-bindPoint-parameter");
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DestroySessionInUse) {
TEST_DESCRIPTION("Try destroying a datagraph pipeline session while it is in use");
SetTargetApiVersion(VK_API_VERSION_1_4);
AddRequiredFeature(vkt::Feature::timelineSemaphore);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
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);
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_command_buffer.End();
VkSemaphoreTypeCreateInfo sem_type = vku::InitStructHelper();
sem_type.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE;
sem_type.initialValue = 0;
VkSemaphoreCreateInfo create_sem = vku::InitStructHelper(&sem_type);
vkt::Semaphore sem(*m_device, create_sem);
VkTimelineSemaphoreSubmitInfo timeline_info = vku::InitStructHelper();
const uint64_t wait_value = 1;
timeline_info.waitSemaphoreValueCount = 1;
timeline_info.pWaitSemaphoreValues = &wait_value;
VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
VkSubmitInfo submit_info = vku::InitStructHelper(&timeline_info);
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &sem.handle();
submit_info.pWaitDstStageMask = &dst_stage_mask;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &m_command_buffer.handle();
vk::QueueSubmit(m_default_queue->handle(), 1, &submit_info, VK_NULL_HANDLE);
m_errorMonitor->SetDesiredError("VUID-vkDestroyDataGraphPipelineSessionARM-session-09793");
vk::DestroyDataGraphPipelineSessionARM(*m_device, session, nullptr);
m_errorMonitor->VerifyFound();
VkSemaphoreSignalInfo signal_sem = vku::InitStructHelper();
signal_sem.semaphore = sem;
signal_sem.value = 1;
vk::SignalSemaphore(*m_device, &signal_sem);
m_default_queue->Wait();
}
TEST_F(NegativeDataGraph, DestroySessionCreatedWithDestroyWithoutCallbacks) {
TEST_DESCRIPTION("Try destroying without callbacks a datagraph pipeline session with callbacks");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
VkDataGraphPipelineSessionARM session;
vk::CreateDataGraphPipelineSessionARM(*m_device, &session_ci, vkt::DefaultAllocator(), &session);
m_errorMonitor->SetDesiredError("VUID-vkDestroyDataGraphPipelineSessionARM-session-09794");
vk::DestroyDataGraphPipelineSessionARM(*m_device, session, nullptr);
m_errorMonitor->VerifyFound();
vk::DestroyDataGraphPipelineSessionARM(*m_device, session, vkt::DefaultAllocator());
vk::CreateDataGraphPipelineSessionARM(*m_device, &session_ci, nullptr, &session);
m_errorMonitor->SetDesiredError("VUID-vkDestroyDataGraphPipelineSessionARM-session-09795");
vk::DestroyDataGraphPipelineSessionARM(*m_device, session, vkt::DefaultAllocator());
m_errorMonitor->VerifyFound();
vk::DestroyDataGraphPipelineSessionARM(*m_device, session, nullptr);
}
TEST_F(NegativeDataGraph, DestroySessionCreatedWithoutDestroyWithCallbacks) {
TEST_DESCRIPTION("Try destroying with callbacks a datagraph pipeline session without callbacks");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
VkDataGraphPipelineSessionARM session;
vk::CreateDataGraphPipelineSessionARM(*m_device, &session_ci, nullptr, &session);
m_errorMonitor->SetDesiredError("VUID-vkDestroyDataGraphPipelineSessionARM-session-09795");
vk::DestroyDataGraphPipelineSessionARM(*m_device, session, vkt::DefaultAllocator());
m_errorMonitor->VerifyFound();
vk::DestroyDataGraphPipelineSessionARM(*m_device, session, nullptr);
}
TEST_F(NegativeDataGraph, CmdDispatchPipelineNotBound) {
TEST_DESCRIPTION(
"Try to add a CmdDispatchDataGraphARM to a command buffer when the pipeline was not bound to "
"VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
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::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-None-08606");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, CmdDispatchDescriptorSetNotBound) {
TEST_DESCRIPTION("Try to dispatch a datagraph when the required descriptor set is not bound");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
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);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatchDataGraphARM-None-08600");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, CmdDispatchSessionNotBound) {
TEST_DESCRIPTION("Try dispatching a graph command when not all required session resources have been bound");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
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-session-09796");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, CmdDispatchSessionPartiallyBound) {
TEST_DESCRIPTION("Dispatch a graph command buffer but bind only some of the required session resources");
AddRequiredExtensions(VK_ARM_DATA_GRAPH_NEURAL_ACCELERATOR_STATISTICS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dataGraphNeuralAcceleratorStatistics);
RETURN_IF_SKIP(InitBasicDataGraph());
// Use NX statistics, so the session requires at least two bind points (transient + nx stats)
// Execute twice, each time binding only one of the bind points
for (auto bind_point : {VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_NEURAL_ACCELERATOR_STATISTICS_ARM,
VK_DATA_GRAPH_PIPELINE_SESSION_BIND_POINT_TRANSIENT_ARM}) {
VkDataGraphPipelineNeuralStatisticsCreateInfoARM ne_stats_info = vku::InitStructHelper();
ne_stats_info.allowNeuralStatistics = VK_TRUE;
vkt::dg::DataGraphPipelineHelper pipeline(*this);
vvl::PnextChainAdd(&pipeline.pipeline_ci_, &ne_stats_info);
pipeline.CreateDataGraphPipeline();
// include a SessionNeuralStatisticsCreateInfo to collect the neural stats
VkDataGraphPipelineSessionNeuralStatisticsCreateInfoARM session_ne_stats_info = vku::InitStructHelper();
session_ne_stats_info.mode = VkNeuralAcceleratorStatisticsModeARM::VK_NEURAL_ACCELERATOR_STATISTICS_MODE_STATISTICS0_ARM;
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper(&session_ne_stats_info);
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
session.AllocSessionMem(device_mem);
std::vector<VkBindDataGraphPipelineSessionMemoryInfoARM> session_bind_infos;
for (uint32_t i = 0; i < session.BindPointsCount(); i++) {
VkDataGraphPipelineSessionBindPointRequirementARM bind_point_req = session.BindPointReqs()[i];
if (bind_point_req.bindPoint != bind_point) {
continue;
}
session_bind_infos.resize(bind_point_req.numObjects);
for (uint32_t j = 0; j < bind_point_req.numObjects; j++) {
session_bind_infos[j] = vku::InitStructHelper();
session_bind_infos[j].session = session;
session_bind_infos[j].memory = device_mem[i];
session_bind_infos[j].bindPoint = bind_point_req.bindPoint;
session_bind_infos[j].objectIndex = j;
}
break;
}
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, static_cast<uint32_t>(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);
VkDataGraphPipelineDispatchInfoARM disp_info = vku::InitStructHelper();
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatchDataGraphARM-session-09796");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, &disp_info);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
};
}
TEST_F(NegativeDataGraph, CmdDispatchProtectedNoFaultUnsupportedUnprotectedCmdBufferProtectedTensor) {
TEST_DESCRIPTION(
"Try dispatching a datagraph with protected resources - bound pipeline tensors have VK_TENSOR_CREATE_PROTECTED_BIT_ARM set "
"- to an unprotected command buffer when protectedNoFault is not supported");
AddRequiredFeature(vkt::Feature::protectedMemory);
RETURN_IF_SKIP(InitBasicDataGraph());
VkPhysicalDeviceProtectedMemoryProperties protected_memory_properties = vku::InitStructHelper();
GetPhysicalDeviceProperties2(protected_memory_properties);
if (protected_memory_properties.protectedNoFault) {
GTEST_SKIP() << "protectedNoFault is supported";
}
vkt::dg::HelperParameters params;
params.protected_tensors = true;
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
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-09800");
m_errorMonitor->SetDesiredError(
"VUID-vkCmdDispatchDataGraphARM-commandBuffer-09800"); // We are using 2 protected resources in this unprotected command
// buffer and so need to log the error twice
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, CmdDispatchProtectedNoFaultUnsupportedProtectedCmdBufferUnprotectedTensor) {
TEST_DESCRIPTION(
"Try dispatching a datagraph with unprotected resources to a protected command buffer - command buffer created with "
"VK_COMMAND_POOL_CREATE_PROTECTED_BIT set - when protectedNoFault is not supported");
SetTargetApiVersion(VK_API_VERSION_1_4);
AddRequiredExtensions(VK_ARM_TENSORS_EXTENSION_NAME);
AddRequiredExtensions(VK_ARM_DATA_GRAPH_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::tensors);
AddRequiredFeature(vkt::Feature::dataGraph);
AddRequiredFeature(vkt::Feature::dataGraphShaderModule);
AddRequiredFeature(vkt::Feature::shaderTensorAccess);
AddRequiredFeature(vkt::Feature::vulkanMemoryModel);
AddRequiredFeature(vkt::Feature::shaderInt8);
AddRequiredFeature(vkt::Feature::protectedMemory);
RETURN_IF_SKIP(InitFramework());
RETURN_IF_SKIP(InitState(nullptr, nullptr, VK_COMMAND_POOL_CREATE_PROTECTED_BIT));
VkPhysicalDeviceProtectedMemoryProperties protected_memory_properties = vku::InitStructHelper();
GetPhysicalDeviceProperties2(protected_memory_properties);
if (protected_memory_properties.protectedNoFault) {
GTEST_SKIP() << "protectedNoFault is supported";
}
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointsCount());
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-09801");
m_errorMonitor->SetDesiredError(
"VUID-vkCmdDispatchDataGraphARM-commandBuffer-09801"); // We are using 2 unprotected resources in this protected command
// buffer and so need to log the error twice
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, CmdDispatchInvalidDescriptorNoUpdate) {
TEST_DESCRIPTION("Try dispatching a datagraph but the descriptor has not been updated");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
auto& bind_point_reqs = session.BindPointReqs();
std::vector<vkt::DeviceMemory> 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());
// update only 1 of 2 descriptors
pipeline.descriptor_set_->WriteDescriptorTensorInfo(0, &pipeline.tensor_views_[0]->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-None-08114");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, CmdDispatchInvalidDescriptorDeletedObject) {
TEST_DESCRIPTION("Try dispatching a datagraph but the tensor or the view are destroyed before dispatch");
RETURN_IF_SKIP(InitBasicDataGraph());
// 2 runs: 1st time delete the tensor, 2nd the view, both make the descriptor invalid
for (uint32_t i = 0; i < 2; i++) {
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
auto& bind_point_reqs = session.BindPointReqs();
std::vector<vkt::DeviceMemory> 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();
// deleting either of these 2 invalidates the descriptor
if (i == 0) {
pipeline.tensors_[0]->Destroy();
} else {
pipeline.tensor_views_[0]->Destroy();
}
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-None-08114");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
}
TEST_F(NegativeDataGraph, CmdDispatchInvalidDescriptorBufferBit) {
TEST_DESCRIPTION(
"Try dispatching a datagraph with VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT set, but using descriptor sets.");
AddRequiredFeature(vkt::Feature::dataGraphDescriptorBuffer);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.pipeline_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT;
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
auto& bind_point_reqs = session.BindPointReqs();
std::vector<vkt::DeviceMemory> 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-None-08115");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, CmdDispatchMissingDescriptorBufferBit) {
TEST_DESCRIPTION(
"Try dispatching a datagraph with descriptor buffers but without the VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT.");
SetTargetApiVersion(VK_API_VERSION_1_4);
AddRequiredExtensions(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::descriptorBuffer);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::dataGraphDescriptorBuffer);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// create a pipeline layout with the required flags
VkDescriptorSetLayoutCreateInfo dslci = vku::InitStructHelper();
dslci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT;
dslci.bindingCount = pipeline.descriptor_set_layout_bindings_.size();
dslci.pBindings = pipeline.descriptor_set_layout_bindings_.data();
vkt::DescriptorSetLayout dsl(*m_device, dslci);
vkt::PipelineLayout pipeline_layout(*m_device, {&dsl});
ASSERT_TRUE(pipeline_layout.initialized());
// set layout for descriptor buffer, but not the flags
// pipeline.pipeline_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT;
pipeline.pipeline_ci_.layout = pipeline_layout;
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
auto& bind_point_reqs = session.BindPointReqs();
std::vector<vkt::DeviceMemory> 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);
vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address);
VkDescriptorBufferBindingInfoEXT dbbi = vku::InitStructHelper();
dbbi.address = buffer.Address();
dbbi.usage = VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT;
vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &dbbi);
uint32_t index = 0;
VkDeviceSize offset = 0;
vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, pipeline_layout, 0, 1, &index,
&offset);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatchDataGraphARM-None-08117");
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatchDataGraphARM-None-08600");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, ShaderModuleCreateInfoInvalidConstantID) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline where the VkDataGraphPipelineShaderModuleCreateInfoARM has a "
"VkDataGraphPipelineConstantARM whose id member is not valid");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
VkDataGraphPipelineConstantARM graph_pipeline_constant = vku::InitStructHelper();
graph_pipeline_constant.id = 42; // Arbitrary value not used by OpGraphConstantARM in shader module
int constant_data = 42;
graph_pipeline_constant.pConstantData = &constant_data;
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &graph_pipeline_constant;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09921");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, TensorSparsitySuppliedMissingDescription) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline with a tensor sparsity structure but missing a tensor description structure");
RETURN_IF_SKIP(InitBasicDataGraph());
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
VkDataGraphPipelineConstantTensorSemiStructuredSparsityInfoARM tensor_sparsity = vku::InitStructHelper();
tensor_sparsity.groupSize = 1;
// GetConstant puts the correct description in the pNext, by overwriting it we lose the description and cause the error
VkDataGraphPipelineConstantARM constant = GetConstant();
constant.pNext = &tensor_sparsity;
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineConstantARM-pNext-09775");
// 9921 will also be triggered since we need a description for this
// Graph Constant ID and we are intentionally not passing one
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09921");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, TensorSparsityDimensionTooLarge) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline with a tensor sparsity structure but the supplied dimension is larger than the "
"dimensionCount in the tensor description supplied");
RETURN_IF_SKIP(InitBasicDataGraph());
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
VkTensorDescriptionARM constant_tensor_desc = DefaultConstantTensorDesc();
VkDataGraphPipelineConstantTensorSemiStructuredSparsityInfoARM tensor_sparsity = vku::InitStructHelper();
tensor_sparsity.groupSize = 1;
tensor_sparsity.dimension = constant_tensor_desc.dimensionCount + 1;
constant_tensor_desc.pNext = &tensor_sparsity;
VkDataGraphPipelineConstantARM constant = GetConstant(constant_tensor_desc);
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineConstantARM-pNext-09776");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, TensorSparsityDescriptionDimensionNotMultipleOfSparsityGroupSize) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline with a tensor sparsity structure but dimension[sparsity->dimension] is not a multiple "
"of sparsity->groupSize");
RETURN_IF_SKIP(InitBasicDataGraph());
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
VkTensorDescriptionARM constant_tensor_desc = DefaultConstantTensorDesc();
VkDataGraphPipelineConstantTensorSemiStructuredSparsityInfoARM tensor_sparsity = vku::InitStructHelper();
tensor_sparsity.dimension = 2;
int64_t dim_2 = constant_tensor_desc.pDimensions[tensor_sparsity.dimension];
ASSERT_TRUE((dim_2 >= 1) && (dim_2 <= static_cast<int64_t>(UINT32_MAX)));
tensor_sparsity.groupSize =
static_cast<uint32_t>(dim_2 - 1); // ensure that dim_2 (the sparsity dimension) is NOT a multiple of groupSize
constant_tensor_desc.pNext = &tensor_sparsity;
VkDataGraphPipelineConstantARM constant = GetConstant(constant_tensor_desc);
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineConstantARM-pNext-09777");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, TensorSparsityDoubleDefinition) {
TEST_DESCRIPTION("Try creating a datagraph pipeline with a tensor sparsity defined twice for the same dimension");
RETURN_IF_SKIP(InitBasicDataGraph());
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
VkTensorDescriptionARM constant_tensor_desc = DefaultConstantTensorDesc();
// add 3 sparsity structures but 2 are for the same dimension -> ERROR
VkDataGraphPipelineConstantTensorSemiStructuredSparsityInfoARM tensor_sparsity0 = vku::InitStructHelper();
tensor_sparsity0.groupSize = 1;
tensor_sparsity0.dimension = 2;
constant_tensor_desc.pNext = &tensor_sparsity0;
VkDataGraphPipelineConstantTensorSemiStructuredSparsityInfoARM tensor_sparsity1 = vku::InitStructHelper();
tensor_sparsity1.groupSize = 2;
tensor_sparsity1.dimension = 3;
tensor_sparsity0.pNext = &tensor_sparsity1;
VkDataGraphPipelineConstantTensorSemiStructuredSparsityInfoARM tensor_sparsity2 = vku::InitStructHelper();
tensor_sparsity2.groupSize = 2;
tensor_sparsity2.dimension = 2;
tensor_sparsity1.pNext = &tensor_sparsity2;
VkDataGraphPipelineConstantARM constant = GetConstant(constant_tensor_desc);
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineConstantARM-pNext-09870");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, GraphConstantTensorWrongID) {
TEST_DESCRIPTION("Try creating a datagraph pipeline with a constant that has an id different from the spirv definition");
RETURN_IF_SKIP(InitBasicDataGraph());
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
VkTensorDescriptionARM desc = DefaultConstantTensorDesc();
VkDataGraphPipelineConstantARM constant = GetConstant(desc);
constant.id = 42;
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
// 9921 triggered 2 times:
// - Vulkan pConstants[x].id = 42 has no correspondence in the spirv code
// - spirv OpGraphConstantARM has no correspondence in the Vulkan pConstants
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09921");
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09921");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, GraphConstantTensorWrongRank) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline with a constant based on a tensor with rank different from the spirv definition");
RETURN_IF_SKIP(InitBasicDataGraph());
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
// define a tensor with rank 3, the spirv has rank 4
VkTensorDescriptionARM desc = vku::InitStructHelper();
const std::vector<int64_t> dimensions{1, 2, 4};
desc.tiling = VK_TENSOR_TILING_LINEAR_ARM;
desc.format = VK_FORMAT_R32_SINT;
desc.dimensionCount = dimensions.size();
desc.pDimensions = dimensions.data();
desc.usage = VK_TENSOR_USAGE_DATA_GRAPH_BIT_ARM;
VkDataGraphPipelineConstantARM constant = GetConstant(desc);
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09921");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, GraphConstantTensorWrongDimensions) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline with a constant based on a tensor with dimensions different from the spirv definition");
RETURN_IF_SKIP(InitBasicDataGraph());
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
// dim[3] is different from the spirv (4)
VkTensorDescriptionARM desc = vku::InitStructHelper();
const std::vector<int64_t> dimensions{1, 2, 4, 1}; // dim[3] is 4 in the spirv
desc.tiling = VK_TENSOR_TILING_LINEAR_ARM;
desc.format = VK_FORMAT_R32_SINT;
desc.dimensionCount = dimensions.size();
desc.pDimensions = dimensions.data();
desc.usage = VK_TENSOR_USAGE_DATA_GRAPH_BIT_ARM;
VkDataGraphPipelineConstantARM constant = GetConstant(desc);
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09921");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, GraphConstantTensorWrongFormat) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline with a constant based on a tensor with format different from the spirv definition");
RETURN_IF_SKIP(InitBasicDataGraph());
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
// try a few different formats, different for bit width, float encoding and type
// compatible VK_FORMAT_R32_SINT and VK_FORMAT_R32_UINT also included
for (auto format : {VK_FORMAT_R32_UINT, VK_FORMAT_R32_SINT, VK_FORMAT_R8_SINT, VK_FORMAT_R8_BOOL_ARM, VK_FORMAT_R32_SFLOAT,
VK_FORMAT_R8_SFLOAT_FPENCODING_FLOAT8E4M3_ARM}) {
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
VkTensorDescriptionARM desc = DefaultConstantTensorDesc();
desc.format = format;
VkDataGraphPipelineConstantARM constant = GetConstant(desc);
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
// SPIRV is signless, so both VK_FORMAT_R32_SINT and VK_FORMAT_R32_UINT must not trigger the error
if (format == VK_FORMAT_R32_SINT || format == VK_FORMAT_R32_UINT) {
pipeline.CreateDataGraphPipeline();
} else {
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09921");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
}
}
TEST_F(NegativeDataGraph, GraphConstantTensorMissingDescription) {
TEST_DESCRIPTION("Try creating a datagraph pipeline with a constant that is missing the tensor description");
RETURN_IF_SKIP(InitBasicDataGraph());
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
// GetConstant puts the correct description in the pNext, remove it to cause the error
VkDataGraphPipelineConstantARM constant = GetConstant();
constant.pNext = nullptr;
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09921");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, GraphConstantTensorWrongTiling) {
TEST_DESCRIPTION("Try creating a datagraph pipeline with a constant which corresponds to a tensor with the incorrect tiling");
RETURN_IF_SKIP(InitBasicDataGraph());
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
VkTensorDescriptionARM desc = DefaultConstantTensorDesc();
desc.tiling = VK_TENSOR_TILING_OPTIMAL_ARM; // should be VK_TENSOR_TILING_LINEAR_ARM
VkDataGraphPipelineConstantARM constant = GetConstant(desc);
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineConstantARM-pNext-09917");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, GraphConstantTensorMissingUsageFlags) {
TEST_DESCRIPTION("Try creating a datagraph pipeline with a constant based on a tensor with the incorrect usage flags");
RETURN_IF_SKIP(InitBasicDataGraph());
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
VkTensorDescriptionARM desc = DefaultConstantTensorDesc();
desc.usage = VK_TENSOR_USAGE_SHADER_BIT_ARM; // should be VK_TENSOR_USAGE_DATA_GRAPH_BIT_ARM
VkDataGraphPipelineConstantARM constant = GetConstant(desc);
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineConstantARM-id-09850");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ResourceTensorWrongDescriptorSet) {
TEST_DESCRIPTION("Try creating a datagraph pipeline with a resource with descriptorSet different from the spirv definition");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// incorrect descriptorSet on one resource
pipeline.resources_[0].descriptorSet = 42;
// 9923 triggered 2 times:
// - Vulkan pResourceInfos[x].descriptorSet = 42 has no correspondence in the spirv code
// - spirv OpVariable has no correspondence in the Vulkan pResourceInfos
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ResourceTensorWrongBinding) {
TEST_DESCRIPTION("Try creating a datagraph pipeline with a resource with binding different from the spirv definition");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// incorrect binding on one resource
pipeline.resources_[0].binding = 42;
// 9923 triggered 2 times:
// - Vulkan pResourceInfos[x].binding = 42 has no correspondence in the spirv code
// - spirv OpVariable has no correspondence in the Vulkan pResourceInfos
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ResourceTensorArrayElementNotZero) {
TEST_DESCRIPTION("Try creating a datagraph pipeline with a resource with arrayElement greater than zero");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// incorrect arrayElement on one resource
pipeline.resources_[0].arrayElement = 42;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ResourceTensorWrongRank) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline with a resource based on a tensor with rank different from the spirv definition");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// define a tensor with rank 3, the spirv has rank 4
auto* desc =
const_cast<VkTensorDescriptionARM*>(vku::FindStructInPNextChain<VkTensorDescriptionARM>(pipeline.resources_[0].pNext));
const std::vector<int64_t> dimensions{1, 4, 16};
desc->dimensionCount = dimensions.size();
desc->pDimensions = dimensions.data();
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ResourceTensorWrongDimensions) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline with a resource based on a tensor with dimensions different from the spirv definition");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// dim[3] is different from the spirv (4)
auto* desc =
const_cast<VkTensorDescriptionARM*>(vku::FindStructInPNextChain<VkTensorDescriptionARM>(pipeline.resources_[0].pNext));
const std::vector<int64_t> dimensions{1, 8, 16, 1}; // dim[3] is 4 in the spirv
desc->dimensionCount = dimensions.size();
desc->pDimensions = dimensions.data();
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ResourceTensorWrongFormat) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline with a resource based on a tensor with format different from the spirv definition");
RETURN_IF_SKIP(InitBasicDataGraph());
// try a few different formats, different for bit width, type and float encoding
// NOTE: VK_FORMAT_R8_SINT included as a sanity check: it is different only by sign from the actual format,
// meaning it is compatible, and it must NOT trigger the VU
for (auto format : {VK_FORMAT_R8_SINT, VK_FORMAT_R8_BOOL_ARM, VK_FORMAT_R32_SINT, VK_FORMAT_R32_SFLOAT,
VK_FORMAT_R8_SFLOAT_FPENCODING_FLOAT8E4M3_ARM}) {
vkt::dg::DataGraphPipelineHelper pipeline(*this);
auto* desc =
const_cast<VkTensorDescriptionARM*>(vku::FindStructInPNextChain<VkTensorDescriptionARM>(pipeline.resources_[0].pNext));
desc->format = format;
if (format == VK_FORMAT_R8_SINT) {
// INT check must not consider the sign, as required by TOSA function specifications
pipeline.CreateDataGraphPipeline();
} else {
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
}
}
TEST_F(NegativeDataGraph, ResourceTensorMissingDescription) {
TEST_DESCRIPTION("Try creating a datagraph pipeline with a resource missing the tensor description");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// cut the connection to the tensor description
pipeline.resources_[0].pNext = nullptr;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ResourceTensorInvalidUsage) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline when the VkTensorDescriptionARM struct in the pNext of resources in resourceInfo do "
"not have a valid Usage member");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// set an incorrect usage in the tensor description
auto* desc =
const_cast<VkTensorDescriptionARM*>(vku::FindStructInPNextChain<VkTensorDescriptionARM>(pipeline.resources_[0].pNext));
desc->usage = VK_TENSOR_USAGE_SHADER_BIT_ARM; // should be VK_TENSOR_USAGE_DATA_GRAPH_BIT_ARM
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineResourceInfoARM-descriptorSet-09851");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ResourceInfoImageLayoutsNoUnifiedImageLayouts) {
TEST_DESCRIPTION(
"Try dispatching a datagraph with image resources without image layout info when unifiedImageLayouts is disabled");
RETURN_IF_SKIP(InitBasicDataGraph(true));
// Need to create a data graph with image resources instead of the usual tensors, so use optical flow.
vkt::dg::OpticalFlowHelper optical_flow(*this);
/* Fail to chain a VkDataGraphPipelineResourceInfoImageLayoutARM structure. Since the unifiedImageLayouts feature is not
* enabled this is invalid usage. */
optical_flow.dg_pipeline_.resources_[0].pNext = nullptr;
optical_flow.CreateDataGraphPipeline();
optical_flow.SetupImageDescriptors();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = optical_flow.dg_pipeline_;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointReqs().size());
session.AllocSessionMem(device_mem);
std::vector<VkBindDataGraphPipelineSessionMemoryInfoARM> session_bind_infos =
DataGraphTest::InitSessionBindInfo(session, device_mem);
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
VkDataGraphPipelineOpticalFlowDispatchInfoARM optical_flow_di = vku::InitStructHelper();
VkDataGraphPipelineDispatchInfoARM pipeline_di = vku::InitStructHelper(&optical_flow_di);
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, optical_flow.dg_pipeline_);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, optical_flow.dg_pipeline_.pipeline_layout_,
0, 1, &optical_flow.dg_pipeline_.descriptor_set_.get()->set_, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineResourceInfoARM-descriptorSet-09962");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, &pipeline_di);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, SessionGetMemoryRequirementsIndexTooLarge) {
TEST_DESCRIPTION("Try to get the memory requirements for a session with an out-of-bounds value for objectIndex");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci, vkt::no_mem);
uint32_t bind_point_req_count = 0;
VkDataGraphPipelineSessionBindPointRequirementsInfoARM bind_point_req_info = vku::InitStructHelper();
bind_point_req_info.session = session;
vk::GetDataGraphPipelineSessionBindPointRequirementsARM(*m_device, &bind_point_req_info, &bind_point_req_count, nullptr);
if (bind_point_req_count == 0) {
GTEST_FAIL() << "No bind points, test incorrect. Possible causes: incorrect spirv, or inconsistency between spirv and "
"tensor/constant declarations\n";
}
std::vector<VkDataGraphPipelineSessionBindPointRequirementARM> bind_point_reqs(bind_point_req_count);
for (auto& bp_req : bind_point_reqs) {
bp_req = vku::InitStructHelper();
}
vk::GetDataGraphPipelineSessionBindPointRequirementsARM(*m_device, &bind_point_req_info, &bind_point_req_count,
bind_point_reqs.data());
VkDataGraphPipelineSessionMemoryRequirementsInfoARM session_mem_reqs = vku::InitStructHelper();
session_mem_reqs.session = session;
session_mem_reqs.bindPoint = bind_point_reqs[0].bindPoint;
session_mem_reqs.objectIndex = bind_point_reqs[0].numObjects; // one over the limit
VkMemoryRequirements2 mem_reqs = vku::InitStructHelper();
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineSessionMemoryRequirementsInfoARM-objectIndex-09855");
vk::GetDataGraphPipelineSessionMemoryRequirementsARM(*m_device, &session_mem_reqs, &mem_reqs);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ShaderUsesSpecConstantsFeatureNotEnabled) {
TEST_DESCRIPTION(
"Try to create a datagraph with a VkSpecializationInfo used in the shader module when the feature is not enabled");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
const VkSpecializationMapEntry entry = {
0, // id
0, // offset
sizeof(uint32_t) // size
};
uint32_t data = 0;
const VkSpecializationInfo specialization_info = {
1,
&entry,
1 * sizeof(uint32_t),
&data,
};
pipeline.shader_module_ci_.pSpecializationInfo = &specialization_info;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineShaderModuleCreateInfoARM-dataGraphSpecializationConstants-09849");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ShaderSpirvUsesOpSpecFeatureNotEnabled) {
TEST_DESCRIPTION(
"Try to create a datagraph with a shader module which contains OpSpec commands when the feature is not enabled");
RETURN_IF_SKIP(InitBasicDataGraph());
// inject a dummy line in the spirv to trigger the error
vkt::dg::ModifiableShaderParameters spirv_params;
spirv_params.types = R"(%dummy_spec_constant = OpSpecConstant %uint 3)";
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvModifyableDataGraph(spirv_params);
// ShaderModule in VkDataGraphPipelineShaderModuleCreateInfoARM::module
{
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineShaderModuleCreateInfoARM-dataGraphSpecializationConstants-09849");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
// ShaderModule in the pNext chain of VkDataGraphPipelineCreateInfoARM
{
spvtools::SpirvTools tools{SPV_ENV_UNIVERSAL_1_6};
std::vector<uint32_t> spirv_binary;
if (!tools.Assemble(spirv_string, &spirv_binary)) {
Monitor().SetError("Failed to compile SPIRV shader module");
return;
}
VkShaderModuleCreateInfo shader_module_create_info = vku::InitStructHelper();
shader_module_create_info.codeSize = spirv_binary.size() * sizeof(uint32_t);
shader_module_create_info.pCode = spirv_binary.data();
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// the helper constructor adds the shader module as VkDataGraphPipelineShaderModuleCreateInfoARM::module, get rid of it
pipeline.shader_module_ci_.module = VK_NULL_HANDLE;
// add the shader info in pNext chain
vvl::PnextChainAdd(&pipeline.pipeline_ci_, &shader_module_create_info);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineShaderModuleCreateInfoARM-dataGraphSpecializationConstants-09849");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeDataGraph, DataGraphShaderModuleCreateInfoIncorrectName) {
TEST_DESCRIPTION(
"Create a datagraph pipeline where VkDataGraphPipelineShaderModuleCreateInfoARM::pName doesn't match the name in the spirv "
"code.");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.shader_module_ci_.pName = "NOT_the_correct_name";
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineShaderModuleCreateInfoARM-pName-09872");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DataGraphShaderModuleCreateInfoHasModuleAndShaderModuleCreateInfo) {
TEST_DESCRIPTION(
"Create a datagraph pipeline where VkDataGraphPipelineShaderModuleCreateInfoARM::module is not null, but it also includes "
"a VkShaderModuleCreateInfo structure in its pNext chain.");
RETURN_IF_SKIP(InitBasicDataGraph());
// the pipeline constructor adds the shader module in the "normal" way, as VkDataGraphPipelineShaderModuleCreateInfoARM::module
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// also add the same ShaderModule in the pNext chain
spvtools::SpirvTools tools{SPV_ENV_UNIVERSAL_1_6};
const std::string& spirv_source = vkt::dg::DataGraphPipelineHelper::GetSpirvBasicDataGraph();
std::vector<uint32_t> spirv_binary;
if (!tools.Assemble(spirv_source, &spirv_binary)) {
Monitor().SetError("Failed to compile SPIRV shader module");
return;
}
VkShaderModuleCreateInfo shader_module_create_info = vku::InitStructHelper();
shader_module_create_info.codeSize = spirv_binary.size() * sizeof(uint32_t);
shader_module_create_info.pCode = spirv_binary.data();
// add the shader info in VkDataGraphPipelineShaderModuleCreateInfoARM::pNext
{
pipeline.shader_module_ci_.pNext = &shader_module_create_info;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineShaderModuleCreateInfoARM-pNext-09873");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
// add the shader info in VkDataGraphPipelineCreateInfoARM::pNext
{
// rearrange the pNext chain, we should get the same result
pipeline.shader_module_ci_.pNext = nullptr;
pipeline.pipeline_ci_.pNext = &shader_module_create_info;
shader_module_create_info.pNext = &pipeline.shader_module_ci_;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineShaderModuleCreateInfoARM-pNext-09873");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeDataGraph, DataGraphShaderModuleCreateInfoInvalidModule) {
TEST_DESCRIPTION(
"Create a datagraph pipeline where VkDataGraphPipelineShaderModuleCreateInfoARM::module is NULL and there is no "
"VkShaderModuleCreateInfo structure in its pNext chain.");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.shader_module_ci_.module = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineShaderModuleCreateInfoARM-pNext-09874");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DataGraphShaderModuleCreateInfoDescriptorBufferNoFeature) {
TEST_DESCRIPTION("Create a datagraph pipeline with the flag for descriptor buffers but the feature is not enabled.");
// NOT adding vkt::Feature::dataGraphDescriptorBuffer
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.pipeline_ci_.flags |= VK_PIPELINE_CREATE_2_DESCRIPTOR_BUFFER_BIT_EXT;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-dataGraphDescriptorBuffer-09885");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DataGraphShaderModuleNoFeature) {
TEST_DESCRIPTION("Try to create a datagraph without the dataGraphShaderModule feature.");
// add all the requirements of InitBasicDataGraph except dataGraphShaderModule
SetTargetApiVersion(VK_API_VERSION_1_4);
AddRequiredExtensions(VK_ARM_TENSORS_EXTENSION_NAME);
AddRequiredExtensions(VK_ARM_DATA_GRAPH_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::tensors);
AddRequiredFeature(vkt::Feature::dataGraph);
AddRequiredFeature(vkt::Feature::shaderTensorAccess);
AddRequiredFeature(vkt::Feature::vulkanMemoryModel);
AddRequiredFeature(vkt::Feature::shaderInt8);
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-dataGraphShaderModule-09886");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DataGraphWrongCreateInfoStructs) {
TEST_DESCRIPTION("None or too many of the required info structures passed in pNext of vkCreateDataGraphPipelinesARM.");
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(InitBasicDataGraph());
// none of the structs included
{
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.pipeline_ci_.pNext = nullptr;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-pNext-09977");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
// too many of the structs included
{
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// a VkDataGraphPipelineShaderModuleCreateInfoARM is already included by the helper, add also
// a VkDataGraphPipelineIdentifierCreateInfoARM (can't have both)
VkDataGraphPipelineIdentifierCreateInfoARM pipeline_id = vku::InitStructHelper();
constexpr uint8_t dummy_data = 1;
pipeline_id.identifierSize = 1;
pipeline_id.pIdentifier = &dummy_data;
vvl::PnextChainAdd(&pipeline.pipeline_ci_, &pipeline_id);
pipeline.pipeline_ci_.flags |= VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
pipeline.pipeline_ci_.pResourceInfos = nullptr;
pipeline.pipeline_ci_.resourceInfoCount = 0;
VkPipelineCache pipeline_cache;
VkPipelineCacheCreateInfo cache_create_info = vku::InitStructHelper();
cache_create_info.initialDataSize = 0;
VkResult err = vk::CreatePipelineCache(device(), &cache_create_info, nullptr, &pipeline_cache);
ASSERT_EQ(VK_SUCCESS, err);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-pNext-09977");
pipeline.CreateDataGraphPipeline(pipeline_cache);
m_errorMonitor->VerifyFound();
vk::DestroyPipelineCache(device(), pipeline_cache, nullptr);
}
}
TEST_F(NegativeDataGraph, DataGraphShaderModuleSpirvArrayWrongSize) {
TEST_DESCRIPTION("Create a datagraph with Vulkan resource arrays not matching the spirv.");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::HelperParameters params;
params.graph_variant = vkt::dg::GraphVariant::AddTensorArraySpirv;
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
// override the DataGraphPipelineHelper constructor: set the wrong array length and recreate the layout
pipeline.descriptor_set_layout_bindings_[0].descriptorCount = 1; // ERROR 9934: the spirv code defines an array of 2
pipeline.descriptor_set_.reset(new OneOffDescriptorSet(pipeline.device_, pipeline.descriptor_set_layout_bindings_));
pipeline.CreatePipelineLayout();
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-layout-09934");
// tensor arrays also triggers VU 9923s (2 tensors, 2 errors)
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DataGraphShaderModuleSpirvRuntimeArraySizeZero) {
TEST_DESCRIPTION("Create a datagraph where a Vulkan resource is a runtime array with count 0.");
SetTargetApiVersion(VK_API_VERSION_1_4);
AddRequiredFeature(vkt::Feature::runtimeDescriptorArray);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::HelperParameters params;
params.graph_variant = vkt::dg::GraphVariant::AddRuntimeTensorArraySpirv;
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
// override the DataGraphPipelineHelper constructor: set the wrong array length and recreate the layout
pipeline.descriptor_set_layout_bindings_[0].descriptorCount = 0; // ERROR 9934: OpTypeRuntimeArray needs > 0
pipeline.descriptor_set_.reset(new OneOffDescriptorSet(pipeline.device_, pipeline.descriptor_set_layout_bindings_));
pipeline.CreatePipelineLayout();
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-layout-09934");
// tensor arrays also triggers VU 9923s (2 tensors, 2 errors)
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DataGraphTensorNoShape) {
TEST_DESCRIPTION("Create a datagraph using tensors without shape.");
RETURN_IF_SKIP(InitBasicDataGraph());
// input and output variables are tensors without a shape, rank only (%tensor_r4)
static const char* tensorNoShapeDataGraphSpirv = R"spirv(
OpCapability GraphARM
OpCapability TensorsARM
OpCapability Int8
OpCapability Shader
OpCapability VulkanMemoryModel
OpCapability Matrix
OpExtension "SPV_ARM_graph"
OpExtension "SPV_ARM_tensors"
OpExtension "SPV_KHR_vulkan_memory_model"
%tosa = OpExtInstImport "TOSA.001000.1"
OpMemoryModel Logical Vulkan
OpName %main_arg_0 "main_arg_0"
OpName %main_res_0 "main_res_0"
OpDecorate %main_arg_0 Binding 0
OpDecorate %main_arg_0 DescriptorSet 0
OpDecorate %main_res_0 Binding 1
OpDecorate %main_res_0 DescriptorSet 0
%i8 = OpTypeInt 8 0
%i32 = OpTypeInt 32 0
%i32_0 = OpConstant %i32 0
%i32_1 = OpConstant %i32 1
%i32_2 = OpConstant %i32 2
%i32_4 = OpConstant %i32 4
%i32_arr_1 = OpTypeArray %i32 %i32_1
%i32_arr_4 = OpTypeArray %i32 %i32_4
%i32_arr_1_2 = OpConstantComposite %i32_arr_1 %i32_2
%i32_arr_1_4 = OpConstantComposite %i32_arr_1 %i32_4
%i32_2_tensor = OpTypeTensorARM %i32 %i32_1 %i32_arr_1_2
%i32_4_tensor = OpTypeTensorARM %i32 %i32_1 %i32_arr_1_4
%tensor_r4 = OpTypeTensorARM %i8 %i32_4
%ptr_tensor_r4 = OpTypePointer UniformConstant %tensor_r4
%i32_2_tensor_2_2 = OpConstantComposite %i32_2_tensor %i32_2 %i32_2
%i32_4_tensor_0_0_0_0 = OpConstantComposite %i32_4_tensor %i32_0 %i32_0 %i32_0 %i32_0
%main_arg_0 = OpVariable %ptr_tensor_r4 UniformConstant
%main_res_0 = OpVariable %ptr_tensor_r4 UniformConstant
%graph_type = OpTypeGraphARM 1 %tensor_r4 %tensor_r4
OpGraphEntryPointARM %graph_0 "main" %main_arg_0 %main_res_0
%graph_0 = OpGraphARM %graph_type
%in_0 = OpGraphInputARM %tensor_r4 %i32_0
%op_0 = OpExtInst %tensor_r4 %tosa MAX_POOL2D %i32_2_tensor_2_2 %i32_2_tensor_2_2 %i32_4_tensor_0_0_0_0 %i32_0 %in_0
%op_1 = OpExtInst %tensor_r4 %tosa MAX_POOL2D %i32_2_tensor_2_2 %i32_2_tensor_2_2 %i32_4_tensor_0_0_0_0 %i32_0 %op_0
OpGraphSetOutputARM %op_1 %i32_0
OpGraphEndARM
)spirv";
vkt::dg::HelperParameters params;
params.spirv_source = tensorNoShapeDataGraphSpirv;
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
// 2 tensors, 2 errors
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09919");
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09919");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DataGraphPipelineIdentifierNoFlag) {
TEST_DESCRIPTION("Create a datagraph with the ARM cache but the wrong flags.");
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
VkDataGraphPipelineIdentifierCreateInfoARM pipeline_id = vku::InitStructHelper();
constexpr uint8_t dummy_data = 1;
pipeline_id.identifierSize = 1;
pipeline_id.pIdentifier = &dummy_data;
// replace the pNext chain, to remove the VkDataGraphPipelineShaderModuleCreateInfoARM added in the helper constructor
pipeline.pipeline_ci_.pNext = &pipeline_id;
// NOT setting VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT in the flags: ERROR
pipeline.pipeline_ci_.pResourceInfos = nullptr;
pipeline.pipeline_ci_.resourceInfoCount = 0;
VkPipelineCache pipeline_cache;
VkPipelineCacheCreateInfo cache_create_info = vku::InitStructHelper();
cache_create_info.initialDataSize = 0;
VkResult err = vk::CreatePipelineCache(device(), &cache_create_info, nullptr, &pipeline_cache);
ASSERT_EQ(VK_SUCCESS, err);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-None-11840");
pipeline.CreateDataGraphPipeline(pipeline_cache);
m_errorMonitor->VerifyFound();
vk::DestroyPipelineCache(device(), pipeline_cache, nullptr);
}
TEST_F(NegativeDataGraph, DataGraphPipelineIdentifierHasResources) {
TEST_DESCRIPTION("Create a datagraph with the ARM cache but resources info still included.");
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
VkDataGraphPipelineIdentifierCreateInfoARM pipeline_id = vku::InitStructHelper();
constexpr uint8_t dummy_data = 1;
pipeline_id.identifierSize = 1;
pipeline_id.pIdentifier = &dummy_data;
// replace the pNext chain, to remove the VkDataGraphPipelineShaderModuleCreateInfoARM added in the helper constructor
pipeline.pipeline_ci_.pNext = &pipeline_id;
// set the correct flags, but leave pResourceInfos
pipeline.pipeline_ci_.flags |= VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
VkPipelineCache pipeline_cache;
VkPipelineCacheCreateInfo cache_create_info = vku::InitStructHelper();
cache_create_info.initialDataSize = 0;
VkResult err = vk::CreatePipelineCache(device(), &cache_create_info, nullptr, &pipeline_cache);
ASSERT_EQ(VK_SUCCESS, err);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-None-12363");
pipeline.CreateDataGraphPipeline(pipeline_cache);
m_errorMonitor->VerifyFound();
vk::DestroyPipelineCache(device(), pipeline_cache, nullptr);
}
TEST_F(NegativeDataGraph, DataGraphCreateInfoResourceCountZero) {
TEST_DESCRIPTION("Create a datagraph with the ARM cache, resource count is zero, but resource pointer is not null.");
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
VkDataGraphPipelineIdentifierCreateInfoARM pipeline_id = vku::InitStructHelper();
constexpr uint8_t dummy_data = 1;
pipeline_id.identifierSize = 1;
pipeline_id.pIdentifier = &dummy_data;
// replace the pNext chain, to remove the VkDataGraphPipelineShaderModuleCreateInfoARM added in the helper constructor
pipeline.pipeline_ci_.pNext = &pipeline_id;
// set the correct flags, set resourceInfoCount to 0, but leave pResourceInfos
pipeline.pipeline_ci_.flags |= VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
pipeline.pipeline_ci_.resourceInfoCount = 0;
VkPipelineCache pipeline_cache;
VkPipelineCacheCreateInfo cache_create_info = vku::InitStructHelper();
cache_create_info.initialDataSize = 0;
VkResult err = vk::CreatePipelineCache(device(), &cache_create_info, nullptr, &pipeline_cache);
ASSERT_EQ(VK_SUCCESS, err);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-resourceInfoCount-12364");
pipeline.CreateDataGraphPipeline(pipeline_cache);
m_errorMonitor->VerifyFound();
vk::DestroyPipelineCache(device(), pipeline_cache, nullptr);
}
TEST_F(NegativeDataGraph, DataGraphCreateInfoNullResources) {
TEST_DESCRIPTION("Create a datagraph but resource count is zero.");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.pipeline_ci_.pResourceInfos = nullptr; // this is to avoid VU 12364
pipeline.pipeline_ci_.resourceInfoCount = 0;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-None-12365");
// we also get 2x this because the spirv still includes 2 resources
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DataGraphPipelineIdentifierNoCache) {
TEST_DESCRIPTION("Create a datagraph using the cache identifier but without a valid cache object.");
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
// add the cache identifier object
VkDataGraphPipelineIdentifierCreateInfoARM pipeline_id = vku::InitStructHelper();
constexpr uint8_t dummy_data = 1;
pipeline_id.identifierSize = 1;
pipeline_id.pIdentifier = &dummy_data;
vvl::PnextChainAdd(&pipeline.pipeline_ci_, &pipeline_id);
pipeline.pipeline_ci_.flags |= VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
// ... but pass a NULL handle for the cache object
VkPipelineCache pipeline_cache = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-vkCreateDataGraphPipelinesARM-pNext-09928");
pipeline.CreateDataGraphPipeline(pipeline_cache);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DataGraphOpGraphConstantARMNoShape) {
TEST_DESCRIPTION("Try to create a datagraph with an OpGraphConstantARM defined on a tensor without shape");
RETURN_IF_SKIP(InitBasicDataGraph());
// inject in the spirv a constant based on a shapeless tensor
vkt::dg::ModifiableShaderParameters spirv_params;
spirv_params.types = R"(
%i32_1_2_4_4_tensor = OpTypeTensorARM %uint %uint_4 %uint_arr_4_1_2_4_4
%tensor_r4 = OpTypeTensorARM %uint %uint_4
%constant_no_shape = OpGraphConstantARM %tensor_r4 0)";
spirv_params.instructions = R"(
%i32_op_1 = OpExtInst %i32_1_2_4_4_tensor %tosa CAST %op_1
%dummy = OpExtInst %i32_1_2_4_4_tensor %tosa ADD %i32_op_1 %constant_no_shape)";
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvModifyableDataGraph(spirv_params);
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
VkDataGraphPipelineConstantARM constant = GetConstant();
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09920");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DataGraphNoConstant) {
TEST_DESCRIPTION("Try to create a datagraph without a required constant.");
RETURN_IF_SKIP(InitBasicDataGraph());
// spirv has a constant, but we don't define it in Vulkan
const std::string spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvConstantDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
// helper constructor does NOT initialize the constant
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09921");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, DataGraphOpGraphConstantARMNotTensor) {
TEST_DESCRIPTION("Try to create a datagraph with an OpGraphConstantARM that is not a tensor");
RETURN_IF_SKIP(InitBasicDataGraph());
// inject in the spirv constants based on a scalar, not tensors
vkt::dg::ModifiableShaderParameters spirv_params;
spirv_params.types = R"(%constant_scalar_min = OpGraphConstantARM %uint 0
%constant_scalar_max = OpGraphConstantARM %uint 128)";
spirv_params.instructions =
"%dummy = OpExtInst %uchar_1_2_4_4_tensor %tosa CLAMP %op_1 %constant_scalar_min %constant_scalar_max %uint_2";
const std::string& spirv_string = vkt::dg::DataGraphPipelineHelper::GetSpirvModifyableDataGraph(spirv_params);
vkt::dg::HelperParameters params;
params.spirv_source = spirv_string.c_str();
m_errorMonitor->SetDesiredError("VUID-VkShaderModuleCreateInfo-pCode-08737");
VkShaderObj shader(*m_device, spirv_string.c_str(), VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_4, SPV_SOURCE_ASM);
m_errorMonitor->VerifyFound();
}
// NOTE: This is meant as a positive test for tensor arrays.
// Right now they are illegal, but they will be legal at some point.
// When this happens, remove the SetDesiredError and move to data_graph_positive.cpp
TEST_F(NegativeDataGraph, DataGraphShaderModuleSpirvArray) {
TEST_DESCRIPTION("Create a datagraph using a tensor array as input.");
RETURN_IF_SKIP(InitBasicDataGraph());
// currently tensor arrays are banned by VU 9923. The mock ICD doesn't create a pipeline, so we can still test
// successfully if we ignore it, but a real driver will actually try to create something illegal, and likely crash
if (!IsPlatformMockICD()) {
GTEST_SKIP() << "Test only supported by MockICD";
}
vkt::dg::HelperParameters params;
params.graph_variant = vkt::dg::GraphVariant::AddTensorArraySpirv;
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
// NOTE: This is meant as a positive test for tensor arrays.
// Right now they are illegal, but they will be legal at some point.
// When this happens, remove the SetDesiredError and move to data_graph_positive.cpp
TEST_F(NegativeDataGraph, DataGraphShaderModuleSpirvRuntimeArray) {
TEST_DESCRIPTION("Create a datagraph using a tensor runtime array as input.");
SetTargetApiVersion(VK_API_VERSION_1_4);
AddRequiredFeature(vkt::Feature::runtimeDescriptorArray);
RETURN_IF_SKIP(InitBasicDataGraph());
// currently tensor arrays are banned by VU 9923. The mock ICD doesn't create a pipeline, so we can still test
// successfully if we ignore it, but a real driver will actually try to create something illegal, and likely crash
if (!IsPlatformMockICD()) {
GTEST_SKIP() << "Test only supported by MockICD";
}
{
// the helper constructs a layout with descriptorCount == 2, matching the size of the spirv array
vkt::dg::HelperParameters params;
params.graph_variant = vkt::dg::GraphVariant::AddRuntimeTensorArraySpirv;
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
// tensor arrays triggers VU 9923, we need to suppress it (2 tensors, 2 errors)
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
{
vkt::dg::HelperParameters params;
params.graph_variant = vkt::dg::GraphVariant::AddRuntimeTensorArraySpirv;
vkt::dg::DataGraphPipelineHelper pipeline(*this, params);
// override the DataGraphPipelineHelper constructor: set a bigger element count, runtime array will handle this
pipeline.descriptor_set_layout_bindings_[0].descriptorCount = 3;
pipeline.descriptor_set_.reset(new OneOffDescriptorSet(pipeline.device_, pipeline.descriptor_set_layout_bindings_));
pipeline.CreatePipelineLayout();
// tensor arrays triggers VU 9923, we need to suppress it (2 tensors, 2 errors)
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09923");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeDataGraph, CmdDispatchWrongPipeline) {
TEST_DESCRIPTION("Try to create a datagraph where session and command buffer are bound to different pipelines.");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
// make a _copy_ of the command buffer pipeline, so everything else checks out, but it's NOT the same object
VkDataGraphPipelineCreateInfoARM pipeline_ci = pipeline.pipeline_ci_;
vkt::Pipeline pipeline_copy(*m_device, pipeline_ci);
// bind the session to the _copy_ pipeline
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline_copy;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
// setup the command buffer with the _default_ pipeline, as usual.
auto& bind_point_reqs = session.BindPointReqs();
std::vector<vkt::DeviceMemory> 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-dataGraphPipeline-09951");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_command_buffer.End();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, CmdDispatchWrongTensorUsage) {
TEST_DESCRIPTION("Create and execute a datagraph where tensors have the wrong usage flag");
RETURN_IF_SKIP(InitBasicDataGraph());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
auto& bind_point_reqs = session.BindPointReqs();
std::vector<vkt::DeviceMemory> 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());
// pass a tensor with the wrong usage into the pipeline
VkTensorDescriptionARM wrong_desc = pipeline.GetTensorDesc(vkt::dg::TensorType::BASIC_SPIRV_IN);
wrong_desc.usage = VK_TENSOR_USAGE_SHADER_BIT_ARM; // should be VK_TENSOR_USAGE_DATA_GRAPH_BIT_ARM
vkt::Tensor wrong_tensor;
vkt::TensorView wrong_view;
pipeline.InitTensor(wrong_tensor, wrong_view, wrong_desc);
pipeline.descriptor_set_->WriteDescriptorTensorInfo(0, &wrong_view.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-pDescription-09900");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, BindPipelineCommandPoolFromWrongQueue) {
TEST_DESCRIPTION("Try to bind a datagraph pipeline with a command buffer using the wrong queue");
RETURN_IF_SKIP(InitBasicDataGraph());
InitRenderTarget();
// find a queue that doesn't support datagraph. Also require supporting either graphics
// or compute, to avoid "VUID-vkCmdBindPipeline-commandBuffer-cmdpool"
uint32_t queueFamilyIndex_no_datagraph_support = vvl::kU32Max;
const auto q_props = m_device->Physical().queue_properties_;
for (uint32_t i = 0; i < (uint32_t)q_props.size(); i++) {
if ((q_props[i].queueFlags & VK_QUEUE_DATA_GRAPH_BIT_ARM) == 0 &&
(q_props[i].queueFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT))) {
queueFamilyIndex_no_datagraph_support = i;
break;
}
}
if (queueFamilyIndex_no_datagraph_support == vvl::kU32Max) {
GTEST_SKIP() << "No queue found that doesn't support VK_QUEUE_DATA_GRAPH_BIT_ARM";
}
vkt::CommandPool commandPool(*m_device, queueFamilyIndex_no_datagraph_support);
vkt::CommandBuffer commandBuffer(*m_device, commandPool);
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
commandBuffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindPipeline-pipelineBindPoint-09910");
vk::CmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, pipeline);
m_errorMonitor->VerifyFound();
commandBuffer.End();
}
TEST_F(NegativeDataGraph, BindWrongBindPoint) {
TEST_DESCRIPTION("Try to bind a graphics pipeline to the datagraph bind point");
RETURN_IF_SKIP(InitBasicDataGraph());
InitRenderTarget();
CreatePipelineHelper pipeline(*this);
pipeline.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdBindPipeline-pipelineBindPoint-09911");
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");
RETURN_IF_SKIP(InitBasicDataGraph());
// 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);
const auto q_props = m_device->Physical().queue_properties_;
for (uint32_t qfi = 0; qfi < n_queue_families; qfi++) {
// the queue must support datagraph
if ((q_props[qfi].queueFlags & VK_QUEUE_DATA_GRAPH_BIT_ARM) == 0) {
continue;
}
uint32_t n_properties;
vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), qfi, &n_properties, nullptr);
std::vector<VkQueueFamilyDataGraphPropertiesARM> properties(n_properties,
{VK_STRUCTURE_TYPE_QUEUE_FAMILY_DATA_GRAPH_PROPERTIES_ARM});
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;
}
}
// TODO: setup the queues so that we don't skip here
if (UINT32_MAX == queue_without_tosa_1_0_idx) {
GTEST_SKIP() << "All the queues supporting datagraph also 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);
auto& bind_point_reqs = session.BindPointReqs();
std::vector<vkt::DeviceMemory> 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();
// run the graph on the wrong queue family (command pool, buffer)
vkt::CommandPool command_pool;
vkt::CommandBuffer command_buffer;
command_pool.Init(*m_device, queue_without_tosa_1_0_idx);
command_buffer.Init(*m_device, command_pool);
command_buffer.Begin();
vk::CmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, pipeline);
vk::CmdBindDescriptorSets(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(command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
command_buffer.End();
}
TEST_F(NegativeDataGraph, OpticalFlowWrongImageFormat) {
TEST_DESCRIPTION("Try to create an optical flow data graph pipeline with an unsupported input image format");
RETURN_IF_SKIP(InitBasicDataGraph(true));
vkt::dg::OpticalFlowHelper optical_flow(*this);
/* Set an unsupported imageFormat. ASTC are block formats, incompatible with optical flow operations. */
optical_flow.optical_flow_ci_.imageFormat = VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineOpticalFlowCreateInfoARM-imageFormat-09968");
(void)optical_flow.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, OpticalFlowWrongFlowVectorFormat) {
TEST_DESCRIPTION("Try to create an optical flow data graph pipeline with an unsupported flow vector image format");
RETURN_IF_SKIP(InitBasicDataGraph(true));
vkt::dg::OpticalFlowHelper optical_flow(*this);
/* Set an unsupported flowVectorFormat. ASTC are block formats, incompatible with optical flow operations. */
optical_flow.optical_flow_ci_.flowVectorFormat = VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineOpticalFlowCreateInfoARM-flowVectorFormat-09969");
(void)optical_flow.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, OpticalFlowWrongCostFormat) {
TEST_DESCRIPTION("Try to create an optical flow data graph pipeline with an unsupported cost image format");
RETURN_IF_SKIP(InitBasicDataGraph(true));
auto opt_flow_properties = vkt::dg::OpticalFlowHelper::QueryOpticalFlowProperties(*this, DefaultQueue()->family_index);
if (!opt_flow_properties.costSupported) {
GTEST_SKIP() << "Cost not supported, skip.";
}
vkt::dg::OpticalFlowHelper optical_flow(*this);
/* Set an unsupported costFormat. ASTC are block formats, incompatible with optical flow operations. */
optical_flow.optical_flow_ci_.costFormat = VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineOpticalFlowCreateInfoARM-costFormat-09970");
(void)optical_flow.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, OpticalFlowWrongHint) {
TEST_DESCRIPTION("Execute optical flow with a wrong meanFlowL1NormHint value");
RETURN_IF_SKIP(InitBasicDataGraph(true));
auto opt_flow_properties = vkt::dg::OpticalFlowHelper::QueryOpticalFlowProperties(*this, DefaultQueue()->family_index);
if (!opt_flow_properties.hintSupported) {
GTEST_SKIP() << "Hint not supported, skip.";
}
vkt::dg::OpticalFlowHelper optical_flow(*this);
optical_flow.CreateDataGraphPipeline();
optical_flow.SetupImageDescriptors();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = optical_flow.dg_pipeline_;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
auto& bind_point_reqs = session.BindPointReqs();
std::vector<vkt::DeviceMemory> 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());
// set a hint that is too high
VkDataGraphPipelineOpticalFlowDispatchInfoARM optical_flow_di = vku::InitStructHelper();
optical_flow_di.meanFlowL1NormHint = optical_flow.optical_flow_ci_.height + 1;
VkDataGraphPipelineDispatchInfoARM pipeline_di = vku::InitStructHelper(&optical_flow_di);
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, optical_flow.dg_pipeline_);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, optical_flow.PipelineLayout(), 0, 1,
optical_flow.DescriptorSet(), 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineOpticalFlowDispatchInfoARM-meanFlowL1NormHint-09976");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, &pipeline_di);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, OpticalFlowNoCacheSession) {
TEST_DESCRIPTION("Dispatch an optical flow pipeline with flags that require cache, but without cache");
RETURN_IF_SKIP(InitBasicDataGraph(true));
vkt::dg::OpticalFlowHelper optical_flow(*this);
optical_flow.CreateDataGraphPipeline();
optical_flow.SetupImageDescriptors();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = optical_flow.dg_pipeline_;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointReqs().size());
session.AllocSessionMem(device_mem);
std::vector<VkBindDataGraphPipelineSessionMemoryInfoARM> session_bind_infos =
DataGraphTest::InitSessionBindInfo(session, device_mem);
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
VkDataGraphPipelineOpticalFlowDispatchInfoARM optical_flow_di = vku::InitStructHelper();
// Set one of the disallowed bits
optical_flow_di.flags = VK_DATA_GRAPH_OPTICAL_FLOW_EXECUTE_REFERENCE_UNCHANGED_BIT_ARM;
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, optical_flow.dg_pipeline_);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, optical_flow.dg_pipeline_.pipeline_layout_,
0, 1, &optical_flow.dg_pipeline_.descriptor_set_.get()->set_, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatchDataGraphARM-pInfo-09964");
VkDataGraphPipelineDispatchInfoARM pipeline_di = vku::InitStructHelper(&optical_flow_di);
vk::CmdDispatchDataGraphARM(m_command_buffer, session, &pipeline_di);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, OpticalFlowDispatchWithoutOpticalFlowCreateInfo) {
TEST_DESCRIPTION("Dispatch an optical flow pipeline without including an optical flow create info");
RETURN_IF_SKIP(InitBasicDataGraph(true));
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
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();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointReqs().size());
session.AllocSessionMem(device_mem);
std::vector<VkBindDataGraphPipelineSessionMemoryInfoARM> session_bind_infos =
DataGraphTest::InitSessionBindInfo(session, device_mem);
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
// Set optical flow dispatch info for `pipeline` which was not created with optical flow create info.
VkDataGraphPipelineOpticalFlowDispatchInfoARM optical_flow_di = vku::InitStructHelper();
VkDataGraphPipelineDispatchInfoARM pipeline_di = vku::InitStructHelper(&optical_flow_di);
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-nodeType-09980");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, &pipeline_di);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, OpticalFlowConnectionsImageLayoutsNoUnifiedImageLayouts) {
TEST_DESCRIPTION(
"Dispatch an optical flow pipeline with a layout definition that require the unifiedImageLayouts feature, but the feature "
"is disabled");
RETURN_IF_SKIP(InitBasicDataGraph(true));
vkt::dg::OpticalFlowHelper optical_flow(*this);
// Set the resource info image layout to VK_IMAGE_LAYOUT_GENERAL, where the connection references a descriptor in the
// VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL layout. Since unifiedImageLayouts feature is not enabled this is invalid usage.
optical_flow.image_layouts_[0].layout = VK_IMAGE_LAYOUT_GENERAL;
optical_flow.CreateDataGraphPipeline();
optical_flow.SetupImageDescriptors();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = optical_flow.dg_pipeline_;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointReqs().size());
session.AllocSessionMem(device_mem);
std::vector<VkBindDataGraphPipelineSessionMemoryInfoARM> session_bind_infos =
DataGraphTest::InitSessionBindInfo(session, device_mem);
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
VkDataGraphPipelineOpticalFlowDispatchInfoARM optical_flow_di = vku::InitStructHelper();
VkDataGraphPipelineDispatchInfoARM pipeline_di = vku::InitStructHelper(&optical_flow_di);
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, optical_flow.dg_pipeline_);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, optical_flow.dg_pipeline_.pipeline_layout_,
0, 1, &optical_flow.dg_pipeline_.descriptor_set_.get()->set_, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatchDataGraphARM-nodeType-09981");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, &pipeline_di);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, OpticalFlowConnectionsImageLayoutsUnifiedImageLayouts) {
TEST_DESCRIPTION("Dispatch an optical flow pipeline with an incorrect layout definition for the unifiedImageLayouts feature");
AddRequiredFeature(vkt::Feature::unifiedImageLayouts);
RETURN_IF_SKIP(InitBasicDataGraph(true));
vkt::dg::OpticalFlowHelper optical_flow(*this);
// Set the resource info image layout to VK_IMAGE_LAYOUT_UNDEFINED, where the connection references a descriptor in the
// VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL layout.
optical_flow.image_layouts_[0].layout = VK_IMAGE_LAYOUT_UNDEFINED;
optical_flow.CreateDataGraphPipeline();
optical_flow.SetupImageDescriptors();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = optical_flow.dg_pipeline_;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
std::vector<vkt::DeviceMemory> device_mem(session.BindPointReqs().size());
session.AllocSessionMem(device_mem);
std::vector<VkBindDataGraphPipelineSessionMemoryInfoARM> session_bind_infos =
DataGraphTest::InitSessionBindInfo(session, device_mem);
vk::BindDataGraphPipelineSessionMemoryARM(*m_device, session_bind_infos.size(), session_bind_infos.data());
VkDataGraphPipelineOpticalFlowDispatchInfoARM optical_flow_di = vku::InitStructHelper();
VkDataGraphPipelineDispatchInfoARM pipeline_di = vku::InitStructHelper(&optical_flow_di);
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, optical_flow.dg_pipeline_);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, optical_flow.dg_pipeline_.pipeline_layout_,
0, 1, &optical_flow.dg_pipeline_.descriptor_set_.get()->set_, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatchDataGraphARM-nodeType-09981");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, &pipeline_di);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeDataGraph, OpticalFlowMissingOpticalFlowCreateInfo) {
TEST_DESCRIPTION("Try to create an optical flow datagraph without a VkDataGraphPipelineOpticalFlowCreateInfoARM structure");
RETURN_IF_SKIP(InitBasicDataGraph(true));
vkt::dg::OpticalFlowHelper optical_flow(*this);
// pipeline_ci_.pNext points to optical_flow_ci_: skip one link to remove it from the chain
optical_flow.dg_pipeline_.pipeline_ci_.pNext = optical_flow.optical_flow_ci_.pNext;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineSingleNodeCreateInfoARM-nodeType-09963");
ASSERT_EQ(VK_ERROR_VALIDATION_FAILED, optical_flow.dg_pipeline_.CreateDataGraphPipeline());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, OpticalFlowWrongNumberOfInputs) {
TEST_DESCRIPTION("Try to create an optical flow datagraph with a missing or too many input connections");
RETURN_IF_SKIP(InitBasicDataGraph(true));
for (uint32_t n : {0, 2}) {
vkt::dg::OfHelperParameters params;
params.n_inputs = n;
vkt::dg::OpticalFlowHelper optical_flow(*this, params);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineSingleNodeCreateInfoARM-nodeType-09978");
ASSERT_EQ(VK_ERROR_VALIDATION_FAILED, optical_flow.dg_pipeline_.CreateDataGraphPipeline());
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeDataGraph, OpticalFlowWrongNumberOfReferences) {
TEST_DESCRIPTION("Try to create an optical flow datagraph with a missing or too many reference connections");
RETURN_IF_SKIP(InitBasicDataGraph(true));
for (uint32_t n : {0, 2}) {
vkt::dg::OfHelperParameters params;
params.n_references = n;
vkt::dg::OpticalFlowHelper optical_flow(*this, params);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineSingleNodeCreateInfoARM-nodeType-09978");
ASSERT_EQ(VK_ERROR_VALIDATION_FAILED, optical_flow.dg_pipeline_.CreateDataGraphPipeline());
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeDataGraph, OpticalFlowWrongNumberOfOutputs) {
TEST_DESCRIPTION("Try to create an optical flow datagraph with a missing or too many output connections");
RETURN_IF_SKIP(InitBasicDataGraph(true));
for (uint32_t n : {0, 2}) {
vkt::dg::OfHelperParameters params;
params.n_outputs = n;
vkt::dg::OpticalFlowHelper optical_flow(*this, params);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineSingleNodeCreateInfoARM-nodeType-09978");
ASSERT_EQ(VK_ERROR_VALIDATION_FAILED, optical_flow.dg_pipeline_.CreateDataGraphPipeline());
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeDataGraph, OpticalFlowWrongNumberOfHints) {
TEST_DESCRIPTION("Try to create an optical flow datagraph with hintGridSize > 0 but missing or too many hint connections");
RETURN_IF_SKIP(InitBasicDataGraph(true));
uint32_t queue_index = DefaultQueue()->family_index;
auto opt_flow_properties = vkt::dg::OpticalFlowHelper::QueryOpticalFlowProperties(*this, queue_index);
if (!opt_flow_properties.hintSupported) {
GTEST_SKIP() << "Hint not supported, skip.";
}
uint32_t hint_grid_size = vkt::dg::OpticalFlowHelper::GetAnyOpticalFlowGridSize(opt_flow_properties);
for (uint32_t n : {0, 2}) {
vkt::dg::OfHelperParameters params;
params.n_hints = n; // force the wrong number of hint images
params.hintGridSize = hint_grid_size;
vkt::dg::OpticalFlowHelper optical_flow(*this, params);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineSingleNodeCreateInfoARM-nodeType-09979");
ASSERT_EQ(VK_ERROR_VALIDATION_FAILED, optical_flow.dg_pipeline_.CreateDataGraphPipeline());
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeDataGraph, OpticalFlowNoHint) {
TEST_DESCRIPTION("Try to create an optical flow datagraph using a hint image but the feature is not supported");
RETURN_IF_SKIP(InitBasicDataGraph(true));
uint32_t n_queue_families;
vk::GetPhysicalDeviceQueueFamilyProperties(Gpu(), &n_queue_families, nullptr);
uint32_t no_hint_index = UINT32_MAX;
const auto q_props = m_device->Physical().queue_properties_;
for (uint32_t qfi = 0; qfi < n_queue_families; qfi++) {
// the queue must support datagraph
if ((q_props[qfi].queueFlags & VK_QUEUE_DATA_GRAPH_BIT_ARM) == 0) {
continue;
}
// and optical flow
auto of_support_property = vkt::dg::OpticalFlowHelper::GetOpticalFlowSupportProperty(*this, qfi);
if (std::nullopt == of_support_property) {
continue;
}
VkQueueFamilyDataGraphOpticalFlowPropertiesARM op_flow_properties = vku::InitStructHelper();
ASSERT_EQ(VK_SUCCESS,
vk::GetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM(
Gpu(), qfi, &of_support_property.value(), reinterpret_cast<VkBaseOutStructure*>(&op_flow_properties)));
if (!op_flow_properties.hintSupported) {
no_hint_index = qfi;
break;
}
}
if (UINT32_MAX == no_hint_index) {
GTEST_SKIP() << "All the queues that support datagraph also support optical flow hint, impossible to create the error "
"condition, skip.";
}
// TODO: use queue with index no_hint_index
vkt::dg::OpticalFlowHelper optical_flow(*this);
// force the hint flag
optical_flow.optical_flow_ci_.flags |= VK_DATA_GRAPH_OPTICAL_FLOW_CREATE_ENABLE_HINT_BIT_ARM;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineOpticalFlowCreateInfoARM-flags-09974");
ASSERT_EQ(VK_ERROR_VALIDATION_FAILED, optical_flow.CreateDataGraphPipeline());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, OpticalFlowNoCost) {
TEST_DESCRIPTION("Try to create an optical flow datagraph using a cost image but the feature is not supported");
RETURN_IF_SKIP(InitBasicDataGraph(true));
uint32_t n_queue_families;
vk::GetPhysicalDeviceQueueFamilyProperties(Gpu(), &n_queue_families, nullptr);
uint32_t no_cost_index = UINT32_MAX;
const auto q_props = m_device->Physical().queue_properties_;
for (uint32_t qfi = 0; qfi < n_queue_families; qfi++) {
// the queue must support datagraph
if ((q_props[qfi].queueFlags & VK_QUEUE_DATA_GRAPH_BIT_ARM) == 0) {
continue;
}
// and optical flow
auto of_support_property = vkt::dg::OpticalFlowHelper::GetOpticalFlowSupportProperty(*this, qfi);
if (std::nullopt == of_support_property) {
continue;
}
VkQueueFamilyDataGraphOpticalFlowPropertiesARM op_flow_properties = vku::InitStructHelper();
ASSERT_EQ(VK_SUCCESS,
vk::GetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM(
Gpu(), qfi, &of_support_property.value(), reinterpret_cast<VkBaseOutStructure*>(&op_flow_properties)));
if (!op_flow_properties.costSupported) {
no_cost_index = qfi;
break;
}
}
if (UINT32_MAX == no_cost_index) {
GTEST_SKIP() << "All the queues that support datagraph also support optical flow cost, impossible to create the error "
"condition, skip.";
}
// TODO: use queue with index no_cost_index
vkt::dg::OpticalFlowHelper optical_flow(*this);
// force the cost flag, and also a format to avoid 9970
optical_flow.optical_flow_ci_.flags |= VK_DATA_GRAPH_OPTICAL_FLOW_CREATE_ENABLE_COST_BIT_ARM;
optical_flow.optical_flow_ci_.costFormat =
optical_flow.GetAnyOpticalFlowFormat(VK_DATA_GRAPH_OPTICAL_FLOW_IMAGE_USAGE_COST_BIT_ARM);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineOpticalFlowCreateInfoARM-flags-09975");
ASSERT_EQ(VK_ERROR_VALIDATION_FAILED, optical_flow.CreateDataGraphPipeline());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, OpticalFlowUnequalGridSizes) {
TEST_DESCRIPTION("Try to create an optical flow datagraph with non-zero hintGridSize not equal to outputGridSize");
RETURN_IF_SKIP(InitBasicDataGraph(true));
// Set different output and hint grid sizes
uint32_t queue_index = DefaultQueue()->family_index;
auto opt_flow_properties = vkt::dg::OpticalFlowHelper::QueryOpticalFlowProperties(*this, queue_index);
vkt::dg::OfHelperParameters params;
params.outputGridSize = vkt::dg::OpticalFlowHelper::GetAnyOpticalFlowGridSize(opt_flow_properties);
params.hintGridSize = vkt::dg::OpticalFlowHelper::GetAnyOpticalFlowGridSize(
opt_flow_properties, static_cast<VkDataGraphOpticalFlowGridSizeFlagBitsARM>(params.outputGridSize + 1));
vkt::dg::OpticalFlowHelper optical_flow(*this, params);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineOpticalFlowCreateInfoARM-hintGridSize-09973");
optical_flow.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, OpticalFlowWrongOutputGridSize) {
TEST_DESCRIPTION("Try to create an optical flow datagraph with a wrong output grid size");
RETURN_IF_SKIP(InitBasicDataGraph(true));
// Set a wrong output grid size that is correct for hint grid size
vkt::dg::OfHelperParameters params;
params.outputGridSize = VK_DATA_GRAPH_OPTICAL_FLOW_GRID_SIZE_UNKNOWN_ARM;
params.hintGridSize = VK_DATA_GRAPH_OPTICAL_FLOW_GRID_SIZE_UNKNOWN_ARM;
vkt::dg::OpticalFlowHelper optical_flow(*this, params);
optical_flow.optical_flow_ci_.flags &= ~VK_DATA_GRAPH_OPTICAL_FLOW_CREATE_ENABLE_HINT_BIT_ARM;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineOpticalFlowCreateInfoARM-outputGridSize-09971");
optical_flow.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, OpticalFlowWrongHintGridSize) {
TEST_DESCRIPTION("Try to create an optical flow datagraph with a wrong hint grid size");
RETURN_IF_SKIP(InitBasicDataGraph(true));
// Set a wrong hint grid size that is correct for output grid size
uint32_t queue_index = DefaultQueue()->family_index;
auto opt_flow_properties = vkt::dg::OpticalFlowHelper::QueryOpticalFlowProperties(*this, queue_index);
vkt::dg::OfHelperParameters params;
params.outputGridSize = vkt::dg::OpticalFlowHelper::GetAnyOpticalFlowGridSize(opt_flow_properties);
params.hintGridSize = params.outputGridSize;
vkt::dg::OpticalFlowHelper optical_flow(*this, params);
optical_flow.optical_flow_ci_.flags &= ~VK_DATA_GRAPH_OPTICAL_FLOW_CREATE_ENABLE_HINT_BIT_ARM;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineOpticalFlowCreateInfoARM-hintGridSize-09972");
optical_flow.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, OpticalFlowWrongWidthHeight) {
TEST_DESCRIPTION("Try to create an optical flow datagraph with wrong image sizes");
RETURN_IF_SKIP(InitBasicDataGraph(true));
uint32_t queue_index = DefaultQueue()->family_index;
auto opt_flow_properties = vkt::dg::OpticalFlowHelper::QueryOpticalFlowProperties(*this, queue_index);
vkt::dg::OfHelperParameters params;
// Set widths and heights that are too low or too high
uint32_t good_width = params.width;
uint32_t good_height = params.height;
uint32_t under_width = opt_flow_properties.minWidth - 1;
uint32_t over_width = opt_flow_properties.maxWidth + 1;
uint32_t under_height = opt_flow_properties.minHeight - 1;
uint32_t over_height = opt_flow_properties.maxHeight + 1;
for (uint32_t w : {under_width, good_width, over_width}) {
for (uint32_t h : {under_height, good_height, over_height}) {
params.width = w;
params.height = h;
vkt::dg::OpticalFlowHelper optical_flow(*this, params);
if (w != good_width) {
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineOpticalFlowCreateInfoARM-width-09966");
}
if (h != good_height) {
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineOpticalFlowCreateInfoARM-height-09967");
}
optical_flow.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
}
}
TEST_F(NegativeDataGraph, ProcessingEnginesGetPropertiesWrongQueue) {
TEST_DESCRIPTION("Request Processing Engine operation properties on a different queue family that does not support them");
RETURN_IF_SKIP(InitBasicDataGraph(true /*optical_flow*/));
// get the available properties on the default queue
uint32_t queue_index = DefaultQueue()->family_index;
uint32_t n_properties = 0;
ASSERT_EQ(VK_SUCCESS, vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), queue_index, &n_properties, nullptr));
std::vector<VkQueueFamilyDataGraphPropertiesARM> data_graph_queue_family_properties(
n_properties, vku::InitStruct<VkQueueFamilyDataGraphPropertiesARM>());
ASSERT_EQ(VK_SUCCESS, vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), queue_index, &n_properties,
data_graph_queue_family_properties.data()));
// same on a different queue
if (SecondQueue() == nullptr) {
GTEST_SKIP() << "Two queue families needed, skip test.";
}
uint32_t other_queue_index = SecondQueue()->family_index;
n_properties = 0;
ASSERT_EQ(VK_SUCCESS, vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), other_queue_index, &n_properties, nullptr));
std::vector<VkQueueFamilyDataGraphPropertiesARM> other_queue_family_data_graph_properties(
n_properties, vku::InitStruct<VkQueueFamilyDataGraphPropertiesARM>());
ASSERT_EQ(VK_SUCCESS, vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), other_queue_index, &n_properties,
other_queue_family_data_graph_properties.data()));
// now ask on the second queue for properties that are present only on the first queue
bool found_unique_property = false;
for (auto& prop : data_graph_queue_family_properties) {
// skip prop if also present in the other queue
if (std::any_of(other_queue_family_data_graph_properties.begin(), other_queue_family_data_graph_properties.end(),
[prop](const auto& other_prop) { return CompareVkQueueFamilyDataGraphPropertiesARM(prop, other_prop); })) {
continue;
}
// The 2 properties that can be supported by the default engine.
// TODO: add more properties for other engines
static constexpr VkPhysicalDeviceDataGraphOperationSupportARM tosa_operation{
VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_SPIRV_EXTENDED_INSTRUCTION_SET_ARM, "TOSA.001000.1", 0};
static constexpr VkPhysicalDeviceDataGraphOperationSupportARM optical_flow_operation{
VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_OPTICAL_FLOW_ARM, "OpticalFlow", 1};
// get the values for the 2 properties supported in the default processing engine.
VkQueueFamilyDataGraphOpticalFlowPropertiesARM op_flow_properties = vku::InitStructHelper();
VkQueueFamilyDataGraphTOSAPropertiesARM tosa_properties = vku::InitStructHelper();
VkBaseOutStructure* pProperties = nullptr;
if (prop.operation.operationType == optical_flow_operation.operationType &&
strcmp(prop.operation.name, optical_flow_operation.name) == 0) {
pProperties = reinterpret_cast<VkBaseOutStructure*>(&op_flow_properties);
} else if (prop.operation.operationType == tosa_operation.operationType &&
strcmp(prop.operation.name, tosa_operation.name) == 0) {
pProperties = reinterpret_cast<VkBaseOutStructure*>(&tosa_properties);
} else {
// some other property that we haven't considered (other engine? Add)
continue;
}
m_errorMonitor->SetDesiredError(
"VUID-vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM-pQueueFamilyDataGraphProperties-09957");
ASSERT_EQ(VK_ERROR_VALIDATION_FAILED, vk::GetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM(
Gpu(), other_queue_index, &prop, pProperties));
m_errorMonitor->VerifyFound();
found_unique_property = true;
}
if (!found_unique_property) {
GTEST_SKIP() << "No queue-family-specific data graph properties available.";
}
}
TEST_F(NegativeDataGraph, ProcessingEnginesGetPropertiesWrongEngine) {
TEST_DESCRIPTION("Request Processing Engine operation properties with the wrong engine");
RETURN_IF_SKIP(InitBasicDataGraph(true /*optical_flow*/));
// get the available properties on the default queue
uint32_t queue_index = DefaultQueue()->family_index;
uint32_t n_properties = 0;
ASSERT_EQ(VK_SUCCESS, vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), queue_index, &n_properties, nullptr));
std::vector<VkQueueFamilyDataGraphPropertiesARM> data_graph_queue_family_properties(
n_properties, vku::InitStruct<VkQueueFamilyDataGraphPropertiesARM>());
ASSERT_EQ(VK_SUCCESS, vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), queue_index, &n_properties,
data_graph_queue_family_properties.data()));
// ask for properties, but switch the engine
bool test_executed = false;
for (auto& prop : data_graph_queue_family_properties) {
// switch the engine in prop
if (prop.engine.type == VK_PHYSICAL_DEVICE_DATA_GRAPH_PROCESSING_ENGINE_TYPE_DEFAULT_ARM) {
prop.engine = {VK_PHYSICAL_DEVICE_DATA_GRAPH_PROCESSING_ENGINE_TYPE_COMPUTE_QCOM, true};
} else {
prop.engine = {VK_PHYSICAL_DEVICE_DATA_GRAPH_PROCESSING_ENGINE_TYPE_DEFAULT_ARM, false};
}
// The 2 properties that can be supported by the default engine.
// TODO: add more properties for other engines
static constexpr VkPhysicalDeviceDataGraphOperationSupportARM tosa_operation{
VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_SPIRV_EXTENDED_INSTRUCTION_SET_ARM, "TOSA.001000.1", 0};
static constexpr VkPhysicalDeviceDataGraphOperationSupportARM optical_flow_operation{
VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_OPTICAL_FLOW_ARM, "OpticalFlow", 1};
// get the values for the 2 properties supported in the default processing engine.
VkQueueFamilyDataGraphOpticalFlowPropertiesARM op_flow_properties = vku::InitStructHelper();
VkQueueFamilyDataGraphTOSAPropertiesARM tosa_properties = vku::InitStructHelper();
VkBaseOutStructure* pProperties = nullptr;
if (prop.operation.operationType == optical_flow_operation.operationType &&
strcmp(prop.operation.name, optical_flow_operation.name) == 0) {
pProperties = reinterpret_cast<VkBaseOutStructure*>(&op_flow_properties);
} else if (prop.operation.operationType == tosa_operation.operationType &&
strcmp(prop.operation.name, tosa_operation.name) == 0) {
pProperties = reinterpret_cast<VkBaseOutStructure*>(&tosa_properties);
} else {
// some other property that we haven't considered (other engine? Add)
continue;
}
m_errorMonitor->SetDesiredError(
"VUID-vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM-pQueueFamilyDataGraphProperties-09957");
ASSERT_EQ(VK_ERROR_VALIDATION_FAILED,
vk::GetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM(Gpu(), queue_index, &prop, pProperties));
m_errorMonitor->VerifyFound();
test_executed = true;
}
if (!test_executed) {
GTEST_SKIP() << "No queue-family-specific data graph properties available.";
}
}
TEST_F(NegativeDataGraph, ProcessingEnginesGetPropertiesWrongType) {
TEST_DESCRIPTION("Request the Processing Engine properties using the wrong structure");
RETURN_IF_SKIP(InitBasicDataGraph(true));
// get the available properties
uint32_t queue_index = DefaultQueue()->family_index;
uint32_t n_properties = 0;
ASSERT_EQ(VK_SUCCESS, vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), queue_index, &n_properties, nullptr));
if (n_properties == 0) {
GTEST_SKIP() << "The physical device does not support any datagraph properties, skip.";
}
std::vector<VkQueueFamilyDataGraphPropertiesARM> data_graph_queue_family_properties(
n_properties, vku::InitStruct<VkQueueFamilyDataGraphPropertiesARM>());
ASSERT_EQ(VK_SUCCESS, vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), queue_index, &n_properties,
data_graph_queue_family_properties.data()));
VkQueueFamilyDataGraphPropertiesARM properties = vku::InitStructHelper(); // WRONG structure!
VkBaseOutStructure* pProperties = reinterpret_cast<VkBaseOutStructure*>(&properties);
m_errorMonitor->SetDesiredError("VUID-vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM-pProperties-09958");
ASSERT_EQ(VK_ERROR_VALIDATION_FAILED, vk::GetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM(
Gpu(), queue_index, &data_graph_queue_family_properties[0], pProperties));
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ProtectedAccessOnlyWithNeuralStatistics) {
TEST_DESCRIPTION(
"Try to create a protected DataGraphPipeline (VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT_EXT) with incompatible neural "
"statistics (VkDataGraphPipelineNeuralStatisticsCreateInfoARM)");
AddRequiredExtensions(VK_ARM_DATA_GRAPH_NEURAL_ACCELERATOR_STATISTICS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dataGraphNeuralAcceleratorStatistics);
AddRequiredFeature(vkt::Feature::protectedMemory);
AddRequiredExtensions(VK_EXT_PIPELINE_PROTECTED_ACCESS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::pipelineProtectedAccess);
RETURN_IF_SKIP(InitBasicDataGraph());
// enable protected access and ask for neural stats: invalid because no data can be returned with protected access
VkDataGraphPipelineNeuralStatisticsCreateInfoARM ne_stats_info = vku::InitStructHelper();
ne_stats_info.allowNeuralStatistics = VK_TRUE;
vkt::dg::DataGraphPipelineHelper helper(*this);
helper.pipeline_ci_.flags = VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT_EXT;
vvl::PnextChainAdd(&helper.pipeline_ci_, &ne_stats_info);
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-flags-09848");
helper.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ProtectedSessionWithNeuralStatistics) {
TEST_DESCRIPTION("Try to request neural statistics in a protected DataGraphPipelineSession (can't return any data)");
AddRequiredExtensions(VK_ARM_DATA_GRAPH_NEURAL_ACCELERATOR_STATISTICS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dataGraphNeuralAcceleratorStatistics);
AddRequiredFeature(vkt::Feature::protectedMemory);
RETURN_IF_SKIP(InitBasicDataGraph());
// create a protected session and ask for neural stats: invalid because no data can be returned with protected access
VkDataGraphPipelineNeuralStatisticsCreateInfoARM ne_stats_info = vku::InitStructHelper();
ne_stats_info.allowNeuralStatistics = VK_TRUE;
vkt::dg::DataGraphPipelineHelper helper(*this);
vvl::PnextChainAdd(&helper.pipeline_ci_, &ne_stats_info);
helper.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = helper;
session_ci.flags = VK_DATA_GRAPH_PIPELINE_SESSION_CREATE_PROTECTED_BIT_ARM;
VkDataGraphPipelineSessionARM session;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineSessionCreateInfoARM-flags-09853");
vk::CreateDataGraphPipelineSessionARM(*m_device, &session_ci, nullptr, &session);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, SessionWithNeuralStatisticsCreateInfoInvalid) {
TEST_DESCRIPTION("Try to create a DataGraphPipelineSession with an invalid NeuralStatisticsCreateInfo");
AddRequiredExtensions(VK_ARM_DATA_GRAPH_NEURAL_ACCELERATOR_STATISTICS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dataGraphNeuralAcceleratorStatistics);
RETURN_IF_SKIP(InitBasicDataGraph());
// pass an INCORRECT request for neural statistics (allowNeuralStatistics == false)
VkDataGraphPipelineNeuralStatisticsCreateInfoARM ne_stats_info = vku::InitStructHelper();
ne_stats_info.allowNeuralStatistics = VK_FALSE; // MUST be true
vkt::dg::DataGraphPipelineHelper helper(*this);
vvl::PnextChainAdd(&helper.pipeline_ci_, &ne_stats_info);
helper.CreateDataGraphPipeline();
// initialize a SessionCreateInfo including a SessionNeuralStatisticsCreateInfo
VkDataGraphPipelineSessionNeuralStatisticsCreateInfoARM session_ne_stats_info = vku::InitStructHelper();
session_ne_stats_info.mode = VkNeuralAcceleratorStatisticsModeARM::VK_NEURAL_ACCELERATOR_STATISTICS_MODE_STATISTICS0_ARM;
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper(&session_ne_stats_info);
session_ci.dataGraphPipeline = helper;
VkDataGraphPipelineSessionARM session = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineSessionCreateInfoARM-pNext-09852");
vk::CreateDataGraphPipelineSessionARM(*m_device, &session_ci, nullptr, &session);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, SessionWithNeuralStatisticsCreateInfoMissing) {
TEST_DESCRIPTION("Try to create Session Neural statistics without initializing (basic) Neural statistics");
AddRequiredExtensions(VK_ARM_DATA_GRAPH_NEURAL_ACCELERATOR_STATISTICS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dataGraphNeuralAcceleratorStatistics);
RETURN_IF_SKIP(InitBasicDataGraph());
// create a pipeline WITHOUT a VkDataGraphPipelineNeuralStatisticsCreateInfoARM in the pNext chain (see previous test)
vkt::dg::DataGraphPipelineHelper helper(*this);
helper.CreateDataGraphPipeline();
// initialize a SessionCreateInfo including a SessionNeuralStatisticsCreateInfo
VkDataGraphPipelineSessionNeuralStatisticsCreateInfoARM session_ne_stats_info = vku::InitStructHelper();
session_ne_stats_info.mode = VkNeuralAcceleratorStatisticsModeARM::VK_NEURAL_ACCELERATOR_STATISTICS_MODE_STATISTICS0_ARM;
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper(&session_ne_stats_info);
session_ci.dataGraphPipeline = helper;
VkDataGraphPipelineSessionARM session = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineSessionCreateInfoARM-pNext-09852");
vk::CreateDataGraphPipelineSessionARM(*m_device, &session_ci, nullptr, &session);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, QueryNeuralStatisticsMissingCreateInfo) {
TEST_DESCRIPTION("Try to query the neural statistics property but the property has not been enabled (missing create_info)");
AddRequiredExtensions(VK_ARM_DATA_GRAPH_NEURAL_ACCELERATOR_STATISTICS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dataGraphNeuralAcceleratorStatistics);
RETURN_IF_SKIP(InitBasicDataGraph());
// create pipeline, WITHOUT a create info for the neural statistics
vkt::dg::DataGraphPipelineHelper helper(*this);
helper.CreateDataGraphPipeline();
// query the neural stats
VkDataGraphPipelineInfoARM pipeline_info = vku::InitStructHelper();
pipeline_info.dataGraphPipeline = helper;
/* query with `pData` null, to get back the required `dataSize`. Enough to trigger the VUID
NOTE: passing an array, to make sure the check is implemented correctly */
std::array<VkDataGraphPipelinePropertyQueryResultARM, 2> query_result;
query_result[0] = vku::InitStructHelper();
query_result[0].property = VK_DATA_GRAPH_PIPELINE_PROPERTY_CREATION_LOG_ARM;
query_result[0].pData = nullptr;
query_result[0].dataSize = 0;
query_result[1] = vku::InitStructHelper();
query_result[1].property = VK_DATA_GRAPH_PIPELINE_PROPERTY_NEURAL_ACCELERATOR_STATISTICS_INFO_ARM;
query_result[1].pData = nullptr;
query_result[1].dataSize = 0;
uint32_t prop_count = query_result.size();
m_errorMonitor->SetDesiredError("VUID-vkGetDataGraphPipelinePropertiesARM-pProperties-09856");
vk::GetDataGraphPipelinePropertiesARM(device(), &pipeline_info, prop_count, query_result.data());
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, QueryNeuralStatisticsAllowedFalse) {
TEST_DESCRIPTION(
"Try to query the neural statistics property but the property has not been enabled (create_info exists but "
"allowNeuralStatistics is false)");
AddRequiredExtensions(VK_ARM_DATA_GRAPH_NEURAL_ACCELERATOR_STATISTICS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dataGraphNeuralAcceleratorStatistics);
RETURN_IF_SKIP(InitBasicDataGraph());
// add the neural stats create info but DISABLE stats
VkDataGraphPipelineNeuralStatisticsCreateInfoARM ne_stats_info = vku::InitStructHelper();
ne_stats_info.allowNeuralStatistics = VK_FALSE; // this MUST be true to get the stats
vkt::dg::DataGraphPipelineHelper helper(*this);
vvl::PnextChainAdd(&helper.pipeline_ci_, &ne_stats_info);
helper.CreateDataGraphPipeline();
// query the neural stats
VkDataGraphPipelineInfoARM pipeline_info = vku::InitStructHelper();
pipeline_info.dataGraphPipeline = helper;
VkDataGraphPipelinePropertyQueryResultARM query_result = vku::InitStructHelper();
// query with pData null, to get back the required dataSize. Enough to trigger the VUID
query_result.property = VK_DATA_GRAPH_PIPELINE_PROPERTY_NEURAL_ACCELERATOR_STATISTICS_INFO_ARM;
query_result.pData = nullptr;
query_result.dataSize = 0;
uint32_t prop_count = 1;
m_errorMonitor->SetDesiredError("VUID-vkGetDataGraphPipelinePropertiesARM-pProperties-09856");
vk::GetDataGraphPipelinePropertiesARM(m_device->handle(), &pipeline_info, prop_count, &query_result);
m_errorMonitor->VerifyFound();
}