blob: e734b7fcc3b6fea1ef5a86ba1abd863679e144c9 [file] [log] [blame]
/*
* 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 <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, 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 when a descriptor has type VK_DESCRIPTOR_TYPE_MUTABLE");
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, PipelineResourceInfoInvalidArrayElement) {
TEST_DESCRIPTION("Try to create a datagraph pipeline where arrayElement in resources is not set to 0");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
auto set_info = [&](vkt::dg::DataGraphPipelineHelper &pipeline) { pipeline.resources_.back().arrayElement = 1; };
vkt::dg::DataGraphPipelineHelper::OneshotTest(*this, set_info, 0, "VUID-VkDataGraphPipelineResourceInfoARM-arrayElement-09779");
}
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();
create_sem.pNext = &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();
submit_info.pNext = &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-09799");
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 command 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-09797");
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 command 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 command with unprotected resoures 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, 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-VkDataGraphPipelineShaderModuleCreateInfoARM-id-09774");
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 and 9850 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");
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineConstantARM-id-09850");
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;
// VU 9921 and 9774 overlap about the ID.
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-pNext-09921");
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineShaderModuleCreateInfoARM-id-09774");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, GraphConstantTensorWrongRank) {
TEST_DESCRIPTION("Try creating a datagraph pipeline with a constant based on a tensor with a 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 sign, bit width, and type
for (auto format : {VK_FORMAT_R8_SINT, VK_FORMAT_R32_UINT, VK_FORMAT_R32_SFLOAT}) {
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;
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;
// VU 9921 and 9850 overlap about the existence of a VkTensorDescriptionARM.
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineConstantARM-id-09850");
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, ResourceIsTensorMissingDescription) {
TEST_DESCRIPTION(
"Try creating a datagraph pipeline when the resources in resourceInfo do not have a VkTensorDescriptionARM in the pNext "
"chain");
InitBasicDataGraph();
RETURN_IF_SKIP(Init());
vkt::dg::DataGraphPipelineHelper pipeline(*this);
for (auto &resource : pipeline.resources_) {
resource.pNext = nullptr;
// each incorrect resource generates a separate error
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineResourceInfoARM-descriptorSet-09851");
}
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeDataGraph, ResourceIsTensorInvalidUsage) {
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());
VkTensorDescriptionARM desc = DefaultDesc();
desc.usage = VK_TENSOR_USAGE_SHADER_BIT_ARM; // should be VK_TENSOR_USAGE_DATA_GRAPH_BIT_ARM
vkt::dg::DataGraphPipelineHelper pipeline(*this);
for (auto &resource : pipeline.resources_) {
resource.pNext = &desc;
// each incorrect resource generates a separate error
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-09763");
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 another dummy one
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;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-pNext-09763");
// it's either this error with resources defined, or VU if no resources
m_errorMonitor->SetAllowedFailureMsg("VUID-VkDataGraphPipelineCreateInfoARM-resourceInfoCount-arraylength");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
}
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");
// currently tensor arrays are effectively banned by this VU, we need to suppress it
m_errorMonitor->SetAllowedFailureMsg("VUID-VkDataGraphPipelineResourceInfoARM-arrayElement-09779");
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");
// currently tensor arrays are effectively banned by this VU, we need to suppress it
m_errorMonitor->SetAllowedFailureMsg("VUID-VkDataGraphPipelineResourceInfoARM-arrayElement-09779");
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;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-None-11840");
// currently we have a conflict with this implicit rule, it will go in a future update
m_errorMonitor->SetAllowedFailureMsg("VUID-VkDataGraphPipelineCreateInfoARM-resourceInfoCount-arraylength");
pipeline.CreateDataGraphPipeline();
m_errorMonitor->VerifyFound();
}
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;
m_errorMonitor->SetDesiredError("VUID-VkDataGraphPipelineCreateInfoARM-None-11841");
pipeline.CreateDataGraphPipeline();
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();
}