blob: 6e0582e1e8c37d364775ba1a2eaf098819b2fd89 [file] [edit]
/*
* Copyright (c) 2025 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");
InitBasicDataGraph();
AddRequiredExtensions(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
AddRequiredExtensions(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
AddRequiredExtensions(VK_EXT_PIPELINE_PROTECTED_ACCESS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::pipelineProtectedAccess);
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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)");
InitBasicDataGraph();
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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)");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
EXPECT_NE(VK_SUCCESS, 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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::protectedMemory);
RETURN_IF_SKIP(Init());
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);
session.GetMemoryReqs();
CheckSessionMemory(session);
// 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");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::protectedMemory);
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
// 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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::timelineSemaphore);
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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, 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");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::protectedMemory);
RETURN_IF_SKIP(Init());
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);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
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);
session.GetMemoryReqs();
CheckSessionMemory(session);
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline.Handle();
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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.Handle());
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, pipeline.pipeline_layout_.handle(), 0, 1,
&pipeline.descriptor_set_.get()->set_, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatchDataGraphARM-None-08114");
vk::CmdDispatchDataGraphARM(m_command_buffer, session.handle(), 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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
// 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.Handle();
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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.Handle());
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, pipeline.pipeline_layout_.handle(), 0, 1,
&pipeline.descriptor_set_.get()->set_, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatchDataGraphARM-None-08114");
vk::CmdDispatchDataGraphARM(m_command_buffer, session.handle(), 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.");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::dataGraphDescriptorBuffer);
RETURN_IF_SKIP(Init());
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.Handle();
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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.Handle());
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_DATA_GRAPH_ARM, pipeline.pipeline_layout_.handle(), 0, 1,
&pipeline.descriptor_set_.get()->set_, 0, nullptr);
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatchDataGraphARM-None-08115");
vk::CmdDispatchDataGraphARM(m_command_buffer, session.handle(), 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.");
InitBasicDataGraph();
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(Init());
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.Handle();
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
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.Handle());
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.handle(), 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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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_R8_UINT;
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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_R8_UINT;
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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
// 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, params);
VkTensorDescriptionARM desc = DefaultConstantTensorDesc();
desc.format = format;
VkDataGraphPipelineConstantARM constant = GetConstant(desc);
pipeline.shader_module_ci_.constantCount = 1;
pipeline.shader_module_ci_.pConstants = &constant;
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-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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
// 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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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, SessionGetMemoryRequirementsIndexTooLarge) {
TEST_DESCRIPTION("Try to get the memory requirements for a session with an out-of-bounds value for objectIndex");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
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, " << IncorrectSpirvMessage;
}
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
// 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.");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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.");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
// 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.");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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.");
InitBasicDataGraph();
// NOT adding vkt::Feature::dataGraphDescriptorBuffer
RETURN_IF_SKIP(Init());
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.");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(Init());
// 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.");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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.");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::runtimeDescriptorArray);
RETURN_IF_SKIP(Init());
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.");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
// 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.");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(Init());
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.");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(Init());
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.");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(Init());
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.");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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.");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
// inject in the spirv a constant based on a shapeless tensor
vkt::dg::ModifiableShaderParameters spirv_params;
spirv_params.types = R"(%tensor_r4 = OpTypeTensorARM %uchar %uint_4
%constant_no_shape = OpGraphConstantARM %tensor_r4 0)";
spirv_params.instructions = "%dummy = OpExtInst %uchar_1_2_4_4_tensor %tosa ADD %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.");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
// get spirv with 2 entrypoints; has a constant in entrypoint 2
const std::string two_entrypoint_spirv = vkt::dg::DataGraphPipelineHelper::GetSpirvMultiEntryTwoDataGraph();
vkt::dg::HelperParameters params;
params.spirv_source = two_entrypoint_spirv.c_str();
params.entrypoint = "entrypoint_2";
// 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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
// 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.");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
// 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.");
InitBasicDataGraph();
AddRequiredFeature(vkt::Feature::runtimeDescriptorArray);
RETURN_IF_SKIP(Init());
// 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.");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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.handle();
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
// 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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
auto& bind_point_reqs = session.BindPointReqs();
std::vector<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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
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");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
// find a queue family that does NOT support TOSA
const VkQueueFamilyDataGraphPropertiesARM tosa_1_0_property{
VK_STRUCTURE_TYPE_QUEUE_FAMILY_DATA_GRAPH_PROPERTIES_ARM,
nullptr,
{VK_PHYSICAL_DEVICE_DATA_GRAPH_PROCESSING_ENGINE_TYPE_DEFAULT_ARM, false},
{VK_PHYSICAL_DEVICE_DATA_GRAPH_OPERATION_TYPE_SPIRV_EXTENDED_INSTRUCTION_SET_ARM, "TOSA.001000.1", 0}};
uint32_t queue_without_tosa_1_0_idx = UINT32_MAX;
uint32_t n_queue_families;
vk::GetPhysicalDeviceQueueFamilyProperties(Gpu(), &n_queue_families, nullptr);
for (uint32_t qfi = 0; qfi < n_queue_families; qfi++) {
uint32_t n_properties;
ASSERT_TRUE(VK_SUCCESS == vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), qfi, &n_properties, nullptr));
std::vector<VkQueueFamilyDataGraphPropertiesARM> properties(n_properties,
{VK_STRUCTURE_TYPE_QUEUE_FAMILY_DATA_GRAPH_PROPERTIES_ARM});
ASSERT_TRUE(VK_SUCCESS ==
vk::GetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(Gpu(), qfi, &n_properties, properties.data()));
bool queue_supports_tosa_1_0 = false;
for (const auto& p : properties) {
if (CompareVkQueueFamilyDataGraphPropertiesARM(tosa_1_0_property, p)) {
queue_supports_tosa_1_0 = true;
break;
}
}
if (!queue_supports_tosa_1_0) {
queue_without_tosa_1_0_idx = qfi;
break;
}
}
if (UINT32_MAX == queue_without_tosa_1_0_idx) {
GTEST_SKIP() << "All queues support TOSA, impossible to create the error condition, skip.";
}
vkt::dg::DataGraphPipelineHelper pipeline(*this);
pipeline.CreateDataGraphPipeline();
VkDataGraphPipelineSessionCreateInfoARM session_ci = vku::InitStructHelper();
session_ci.dataGraphPipeline = pipeline;
vkt::DataGraphPipelineSession session(*m_device, session_ci);
session.GetMemoryReqs();
CheckSessionMemory(session);
auto& bind_point_reqs = session.BindPointReqs();
std::vector<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-commandBuffer-09941");
vk::CmdDispatchDataGraphARM(m_command_buffer, session, nullptr);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}