blob: 2f476df4411ad751ff563d9dcd16621c1904cb8b [file] [log] [blame]
/*
* Copyright (c) 2015-2022 The Khronos Group Inc.
* Copyright (c) 2015-2022 Valve Corporation
* Copyright (c) 2015-2022 LunarG, Inc.
* Copyright (c) 2015-2022 Google, Inc.
*
* 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
*
* Author: Nathaniel Cesario <nathaniel@lunarg.com>
*/
#include "layer_validation_tests.h"
#include "vk_extension_helper.h"
#include <algorithm>
#include <array>
#include <chrono>
#include <memory>
#include <mutex>
#include <thread>
#include "cast_utils.h"
class VkGraphicsLibraryLayerTest : public VkLayerTest {};
TEST_F(VkGraphicsLibraryLayerTest, InvalidDSLs) {
TEST_DESCRIPTION("Create a pipeline layout with invalid descriptor set layouts");
m_errorMonitor->ExpectSuccess();
ASSERT_NO_FATAL_FAILURE(Init());
VkDescriptorSetLayoutBinding dsl_binding = {};
dsl_binding.binding = 0;
dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
dsl_binding.descriptorCount = 1;
dsl_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
dsl_binding.pImmutableSamplers = nullptr;
auto dsl_ci = LvlInitStruct<VkDescriptorSetLayoutCreateInfo>();
dsl_ci.bindingCount = 1;
dsl_ci.pBindings = &dsl_binding;
vk_testing::DescriptorSetLayout dsl(*m_device, dsl_ci);
m_errorMonitor->VerifyNotFound();
std::vector<const vk_testing::DescriptorSetLayout*> dsls = {&dsl, nullptr};
VkPipelineLayoutCreateInfo pipeline_layout_ci = LvlInitStruct<VkPipelineLayoutCreateInfo>();
pipeline_layout_ci.pushConstantRangeCount = 0;
pipeline_layout_ci.pPushConstantRanges = nullptr;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-06561");
vk_testing::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci, dsls);
m_errorMonitor->VerifyFound();
}
TEST_F(VkGraphicsLibraryLayerTest, GPLInvalidDSLs) {
TEST_DESCRIPTION("Create a pipeline layout with invalid descriptor set layouts with VK_EXT_grahpics_pipeline_library enabled");
m_errorMonitor->ExpectSuccess();
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState());
VkDescriptorSetLayoutBinding dsl_binding = {};
dsl_binding.binding = 0;
dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
dsl_binding.descriptorCount = 1;
dsl_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
dsl_binding.pImmutableSamplers = nullptr;
auto dsl_ci = LvlInitStruct<VkDescriptorSetLayoutCreateInfo>();
dsl_ci.bindingCount = 1;
dsl_ci.pBindings = &dsl_binding;
vk_testing::DescriptorSetLayout dsl(*m_device, dsl_ci);
m_errorMonitor->VerifyNotFound();
std::vector<const vk_testing::DescriptorSetLayout *> dsls = {&dsl, nullptr};
VkPipelineLayoutCreateInfo pipeline_layout_ci = LvlInitStruct<VkPipelineLayoutCreateInfo>();
pipeline_layout_ci.pushConstantRangeCount = 0;
pipeline_layout_ci.pPushConstantRanges = nullptr;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineLayoutCreateInfo-graphicsPipelineLibrary-06753");
vk_testing::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci, dsls);
m_errorMonitor->VerifyFound();
}
TEST_F(VkGraphicsLibraryLayerTest, InvalidIndependentSetsLinkOnly) {
TEST_DESCRIPTION("Link pre-raster and FS subsets with invalid VkPipelineLayout create flags");
m_errorMonitor->ExpectSuccess();
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
auto gpl_features = LvlInitStruct<VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT>();
auto features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>(&gpl_features);
vk::GetPhysicalDeviceFeatures2(gpu(), &features2);
if (!gpl_features.graphicsPipelineLibrary) {
printf("%s VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT::graphicsPipelineLibrary not supported", kSkipPrefix);
return;
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
// Layout, renderPass, and subpass all need to be shared across libraries in the same executable pipeline
VkRenderPass render_pass = VK_NULL_HANDLE;
uint32_t subpass = 0;
CreatePipelineHelper pre_raster_lib(*this);
{
const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, bindStateVertShaderText);
auto vs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
vs_ci.codeSize = vs_spv.size() * sizeof(decltype(vs_spv)::value_type);
vs_ci.pCode = vs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&vs_ci);
stage_ci.stage = VK_SHADER_STAGE_VERTEX_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
pre_raster_lib.InitPreRasterLibInfo(1, &stage_ci);
pre_raster_lib.pipeline_layout_ci_.flags |= VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT;
pre_raster_lib.InitState();
ASSERT_VK_SUCCESS(pre_raster_lib.CreateGraphicsPipeline());
}
render_pass = pre_raster_lib.gp_ci_.renderPass;
subpass = pre_raster_lib.gp_ci_.subpass;
CreatePipelineHelper frag_shader_lib(*this);
{
const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, bindStateFragShaderText);
auto fs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
fs_ci.codeSize = fs_spv.size() * sizeof(decltype(fs_spv)::value_type);
fs_ci.pCode = fs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&fs_ci);
stage_ci.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
frag_shader_lib.InitFragmentLibInfo(1, &stage_ci);
frag_shader_lib.InitState();
// frag_shader_lib's layout will not be created with VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT, which will trigger
// the desired error
frag_shader_lib.gp_ci_.renderPass = render_pass;
frag_shader_lib.gp_ci_.subpass = subpass;
ASSERT_VK_SUCCESS(frag_shader_lib.CreateGraphicsPipeline());
}
m_errorMonitor->VerifyNotFound();
VkPipeline libraries[2] = {
pre_raster_lib.pipeline_,
frag_shader_lib.pipeline_,
};
auto link_info = LvlInitStruct<VkPipelineLibraryCreateInfoKHR>();
link_info.libraryCount = size(libraries);
link_info.pLibraries = libraries;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-pLibraries-06615");
auto lib_ci = LvlInitStruct<VkGraphicsPipelineCreateInfo>(&link_info);
vk_testing::Pipeline lib(*m_device, lib_ci);
m_errorMonitor->VerifyFound();
}
TEST_F(VkGraphicsLibraryLayerTest, InvalidIndependentSetsLinkCreate) {
TEST_DESCRIPTION("Create pre-raster subset while linking FS subset with invalid VkPipelineLayout create flags");
m_errorMonitor->ExpectSuccess();
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
auto gpl_features = LvlInitStruct<VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT>();
auto features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>(&gpl_features);
vk::GetPhysicalDeviceFeatures2(gpu(), &features2);
if (!gpl_features.graphicsPipelineLibrary) {
printf("%s VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT::graphicsPipelineLibrary not supported", kSkipPrefix);
return;
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
// Layout, renderPass, and subpass all need to be shared across libraries in the same executable pipeline
VkRenderPass render_pass = VK_NULL_HANDLE;
uint32_t subpass = 0;
CreatePipelineHelper pre_raster_lib(*this);
{
const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, bindStateVertShaderText);
auto vs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
vs_ci.codeSize = vs_spv.size() * sizeof(decltype(vs_spv)::value_type);
vs_ci.pCode = vs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&vs_ci);
stage_ci.stage = VK_SHADER_STAGE_VERTEX_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
pre_raster_lib.InitPreRasterLibInfo(1, &stage_ci);
pre_raster_lib.pipeline_layout_ci_.flags |= VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT;
pre_raster_lib.InitState();
ASSERT_VK_SUCCESS(pre_raster_lib.CreateGraphicsPipeline());
}
render_pass = pre_raster_lib.gp_ci_.renderPass;
subpass = pre_raster_lib.gp_ci_.subpass;
CreatePipelineHelper frag_shader_lib(*this);
{
const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, bindStateFragShaderText);
auto fs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
fs_ci.codeSize = fs_spv.size() * sizeof(decltype(fs_spv)::value_type);
fs_ci.pCode = fs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&fs_ci);
stage_ci.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
auto link_info = LvlInitStruct<VkPipelineLibraryCreateInfoKHR>();
link_info.libraryCount = 1;
link_info.pLibraries = &pre_raster_lib.pipeline_;
frag_shader_lib.InitFragmentLibInfo(1, &stage_ci, &link_info);
frag_shader_lib.InitState();
m_errorMonitor->VerifyNotFound();
// frag_shader_lib's layout will not be created with VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT, which will trigger
// the desired error
frag_shader_lib.gp_ci_.renderPass = render_pass;
frag_shader_lib.gp_ci_.subpass = subpass;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-06614");
frag_shader_lib.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
}
TEST_F(VkGraphicsLibraryLayerTest, InvalidDescriptorSets) {
TEST_DESCRIPTION(
"Attempt to bind invalid descriptor sets with and without VK_EXT_graphics_pipeline_library and independent sets");
m_errorMonitor->ExpectSuccess();
ASSERT_NO_FATAL_FAILURE(Init());
// Prepare descriptors
OneOffDescriptorSet ds(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
OneOffDescriptorSet ds2(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
std::array<VkDescriptorSet, 2> sets = {
ds.set_,
VK_NULL_HANDLE, // Triggers 06563
};
VkPipelineLayoutObj pipeline_layout(m_device, {&ds.layout_, &ds2.layout_});
m_commandBuffer->begin();
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindDescriptorSets-pDescriptorSets-06563");
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0,
static_cast<uint32_t>(sets.size()), sets.data(), 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(VkGraphicsLibraryLayerTest, InvalidDescriptorSetsGPL) {
TEST_DESCRIPTION("Attempt to bind invalid descriptor sets with and with VK_EXT_graphics_pipeline_library");
m_errorMonitor->ExpectSuccess();
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState());
// Prepare descriptors
OneOffDescriptorSet ds(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
OneOffDescriptorSet ds2(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
std::array<VkDescriptorSet, 2> sets = {
ds.set_,
VK_NULL_HANDLE,
};
VkPipelineLayoutObj pipeline_layout(m_device, {&ds.layout_, &ds2.layout_});
m_commandBuffer->begin();
m_errorMonitor->VerifyNotFound();
// Now bind with a layout that was _not_ created with independent sets, which should trigger 06754
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindDescriptorSets-graphicsPipelineLibrary-06754");
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0,
static_cast<uint32_t>(sets.size()), sets.data(), 0, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(VkGraphicsLibraryLayerTest, MissingDSState) {
TEST_DESCRIPTION("Create a library with fragment shader state, but no fragment output state, and invalid DS state");
m_errorMonitor->ExpectSuccess();
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
SetTargetApiVersion(VK_API_VERSION_1_2);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (DeviceValidationVersion() < VK_API_VERSION_1_2) {
GTEST_SKIP() << "At least Vulkan version 1.2 is required";
}
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
auto dynamic_rendering_features = LvlInitStruct<VkPhysicalDeviceDynamicRenderingFeaturesKHR>();
auto gpl_features = LvlInitStruct<VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT>(&dynamic_rendering_features);
auto features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>(&gpl_features);
vk::GetPhysicalDeviceFeatures2(gpu(), &features2);
if (!gpl_features.graphicsPipelineLibrary) {
printf("%s VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT::graphicsPipelineLibrary not supported", kSkipPrefix);
return;
}
if (!dynamic_rendering_features.dynamicRendering) {
printf("%s Test requires (unsupported) dynamicRendering , skipping\n", kSkipPrefix);
return;
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
CreatePipelineHelper frag_shader_lib(*this);
const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, bindStateFragShaderText);
auto fs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
fs_ci.codeSize = fs_spv.size() * sizeof(decltype(fs_spv)::value_type);
fs_ci.pCode = fs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&fs_ci);
stage_ci.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
frag_shader_lib.InitFragmentLibInfo(1, &stage_ci);
frag_shader_lib.InitState();
m_errorMonitor->VerifyNotFound();
frag_shader_lib.gp_ci_.renderPass = VK_NULL_HANDLE;
frag_shader_lib.gp_ci_.pDepthStencilState = nullptr;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06590");
frag_shader_lib.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(VkGraphicsLibraryLayerTest, ImplicitVUIDs) {
TEST_DESCRIPTION("Test various VUIDs that were previously implicit, but now explicit due to VK_EXT_graphics_pipeline_library");
m_errorMonitor->ExpectSuccess();
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
CreatePipelineHelper pipe(*this);
pipe.InitInfo();
pipe.InitState();
pipe.LateBindPipelineInfo();
m_errorMonitor->VerifyNotFound();
pipe.gp_ci_.layout = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-layout-06602");
pipe.CreateGraphicsPipeline(true, false);
m_errorMonitor->VerifyFound();
pipe.gp_ci_.layout = pipe.pipeline_layout_.handle();
pipe.gp_ci_.renderPass = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06574");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06603");
pipe.CreateGraphicsPipeline(true, false);
m_errorMonitor->VerifyFound();
pipe.gp_ci_.renderPass = renderPass();
pipe.gp_ci_.stageCount = 0;
pipe.gp_ci_.pStages = nullptr;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-pStages-06600");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-stageCount-06604");
pipe.CreateGraphicsPipeline(true, false);
m_errorMonitor->VerifyFound();
}
TEST_F(VkGraphicsLibraryLayerTest, InvalidCreateStateGPL) {
TEST_DESCRIPTION("Create invalid graphics pipeline state with VK_EXT_graphics_pipeline_library enabled");
m_errorMonitor->ExpectSuccess();
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (DeviceValidationVersion() < VK_API_VERSION_1_2) {
GTEST_SKIP() << "At least Vulkan version 1.2 is required";
}
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
// Do _not_ enable VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT::graphicsPipelineLibrary
ASSERT_NO_FATAL_FAILURE(InitState());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
{
// Test creating a pipeline with incorrect create flags
CreatePipelineHelper pipe(*this);
pipe.InitInfo();
pipe.InitState();
pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-graphicsPipelineLibrary-06606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-06608");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
{
m_errorMonitor->ExpectSuccess();
// Test creating a pipeline with incomplete state, but feature is not enabled
const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, bindStateVertShaderText);
auto vs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
vs_ci.codeSize = vs_spv.size() * sizeof(decltype(vs_spv)::value_type);
vs_ci.pCode = vs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&vs_ci);
stage_ci.stage = VK_SHADER_STAGE_VERTEX_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
CreatePipelineHelper pipe(*this);
pipe.InitPreRasterLibInfo(1, &stage_ci);
pipe.InitState();
m_errorMonitor->VerifyNotFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-graphicsPipelineLibrary-06606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-graphicsPipelineLibrary-06607");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
}
TEST_F(VkGraphicsLibraryLayerTest, InvalidLinkOptimization) {
TEST_DESCRIPTION("Create graphics pipeline libraries with mismatching link-time optimization flags");
m_errorMonitor->ExpectSuccess();
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (DeviceValidationVersion() < VK_API_VERSION_1_2) {
GTEST_SKIP() << "At least Vulkan version 1.2 is required";
}
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
auto gpl_features = LvlInitStruct<VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT>();
auto features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>(&gpl_features);
vk::GetPhysicalDeviceFeatures2(gpu(), &features2);
if (!gpl_features.graphicsPipelineLibrary) {
printf("%s VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT::graphicsPipelineLibrary not supported", kSkipPrefix);
return;
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
CreatePipelineHelper vertex_input_lib(*this);
vertex_input_lib.InitVertexInputLibInfo();
vertex_input_lib.InitState();
// Ensure this library is created _without_ VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT
vertex_input_lib.gp_ci_.flags &= ~VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT;
ASSERT_VK_SUCCESS(vertex_input_lib.CreateGraphicsPipeline(true, false));
VkPipeline libraries[1] = {
vertex_input_lib.pipeline_,
};
auto link_info = LvlInitStruct<VkPipelineLibraryCreateInfoKHR>();
link_info.libraryCount = size(libraries);
link_info.pLibraries = libraries;
const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, bindStateVertShaderText);
auto vs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
vs_ci.codeSize = vs_spv.size() * sizeof(decltype(vs_spv)::value_type);
vs_ci.pCode = vs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&vs_ci);
stage_ci.stage = VK_SHADER_STAGE_VERTEX_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
{
CreatePipelineHelper pre_raster_lib(*this);
pre_raster_lib.InitPreRasterLibInfo(1, &stage_ci);
pre_raster_lib.InitState();
m_errorMonitor->VerifyNotFound();
// Creating with VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT while linking against a library without
// VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT is invalid
pre_raster_lib.gp_ci_.flags |= VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT;
pre_raster_lib.gpl_info->pNext = &link_info;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-06609");
pre_raster_lib.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
{
m_errorMonitor->ExpectSuccess();
CreatePipelineHelper pre_raster_lib(*this);
pre_raster_lib.InitPreRasterLibInfo(1, &stage_ci);
pre_raster_lib.InitState();
m_errorMonitor->VerifyNotFound();
// Creating with VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT while linking against a library without
// VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT is invalid
pre_raster_lib.gp_ci_.flags |= VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT;
pre_raster_lib.gpl_info->pNext = &link_info;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-06610");
pre_raster_lib.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
}
TEST_F(VkGraphicsLibraryLayerTest, InvalidDSLShaderBindingsNullInCreate) {
TEST_DESCRIPTION("Link pre-raster state while creating FS state with invalid null DSL + shader stage bindings");
m_errorMonitor->ExpectSuccess();
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
auto vkGetPhysicalDeviceFeatures2KHR = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
vk::GetInstanceProcAddr(instance(), "vkGetPhysicalDeviceFeatures2KHR"));
ASSERT_TRUE(vkGetPhysicalDeviceFeatures2KHR != nullptr);
auto gpl_features = LvlInitStruct<VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT>();
auto features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>(&gpl_features);
vkGetPhysicalDeviceFeatures2KHR(gpu(), &features2);
if (!gpl_features.graphicsPipelineLibrary) {
GTEST_SKIP() << "VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT::graphicsPipelineLibrary not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
// Prepare descriptors
OneOffDescriptorSet ds(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr},
});
OneOffDescriptorSet ds2(
m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
VkPipelineLayoutObj pipeline_layout_vs(m_device, {&ds.layout_, &ds2.layout_}, {},
VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT);
VkPipelineLayoutObj pipeline_layout_fs(m_device, {&ds.layout_, nullptr}, {},
VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT);
// Layout, renderPass, and subpass all need to be shared across libraries in the same executable pipeline
VkRenderPass render_pass = VK_NULL_HANDLE;
uint32_t subpass = 0;
CreatePipelineHelper pre_raster_lib(*this);
{
const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, bindStateVertShaderText);
auto vs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
vs_ci.codeSize = vs_spv.size() * sizeof(decltype(vs_spv)::value_type);
vs_ci.pCode = vs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&vs_ci);
stage_ci.stage = VK_SHADER_STAGE_VERTEX_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
pre_raster_lib.InitPreRasterLibInfo(1, &stage_ci);
pre_raster_lib.InitState();
pre_raster_lib.gp_ci_.layout = pipeline_layout_vs.handle();
ASSERT_VK_SUCCESS(pre_raster_lib.CreateGraphicsPipeline(true, false));
}
render_pass = pre_raster_lib.gp_ci_.renderPass;
subpass = pre_raster_lib.gp_ci_.subpass;
CreatePipelineHelper frag_shader_lib(*this);
{
const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, bindStateFragShaderText);
auto fs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
fs_ci.codeSize = fs_spv.size() * sizeof(decltype(fs_spv)::value_type);
fs_ci.pCode = fs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&fs_ci);
stage_ci.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
auto link_info = LvlInitStruct<VkPipelineLibraryCreateInfoKHR>();
link_info.libraryCount = 1;
link_info.pLibraries = &pre_raster_lib.pipeline_;
frag_shader_lib.InitFragmentLibInfo(1, &stage_ci, &link_info);
frag_shader_lib.InitState();
m_errorMonitor->VerifyNotFound();
frag_shader_lib.gp_ci_.renderPass = render_pass;
frag_shader_lib.gp_ci_.subpass = subpass;
frag_shader_lib.gp_ci_.layout = pipeline_layout_fs.handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-06756");
frag_shader_lib.CreateGraphicsPipeline(true, false);
m_errorMonitor->VerifyFound();
}
}
TEST_F(VkGraphicsLibraryLayerTest, InvalidDSLShaderBindingsNullInLink) {
TEST_DESCRIPTION("Link pre-raster state with invalid null DSL + shader stage bindings while creating FS state");
m_errorMonitor->ExpectSuccess();
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
auto vkGetPhysicalDeviceFeatures2KHR = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
vk::GetInstanceProcAddr(instance(), "vkGetPhysicalDeviceFeatures2KHR"));
ASSERT_TRUE(vkGetPhysicalDeviceFeatures2KHR != nullptr);
auto gpl_features = LvlInitStruct<VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT>();
auto features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>(&gpl_features);
vkGetPhysicalDeviceFeatures2KHR(gpu(), &features2);
if (!gpl_features.graphicsPipelineLibrary) {
GTEST_SKIP() << "VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT::graphicsPipelineLibrary not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
// Prepare descriptors
OneOffDescriptorSet ds(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr},
});
OneOffDescriptorSet ds2(
m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
VkPipelineLayoutObj pipeline_layout_vs(m_device, {&ds.layout_, nullptr}, {},
VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT);
VkPipelineLayoutObj pipeline_layout_fs(m_device, {&ds.layout_, &ds2.layout_}, {},
VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT);
// Layout, renderPass, and subpass all need to be shared across libraries in the same executable pipeline
VkRenderPass render_pass = VK_NULL_HANDLE;
uint32_t subpass = 0;
CreatePipelineHelper pre_raster_lib(*this);
{
const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, bindStateVertShaderText);
auto vs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
vs_ci.codeSize = vs_spv.size() * sizeof(decltype(vs_spv)::value_type);
vs_ci.pCode = vs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&vs_ci);
stage_ci.stage = VK_SHADER_STAGE_VERTEX_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
pre_raster_lib.InitPreRasterLibInfo(1, &stage_ci);
pre_raster_lib.InitState();
pre_raster_lib.gp_ci_.layout = pipeline_layout_vs.handle();
ASSERT_VK_SUCCESS(pre_raster_lib.CreateGraphicsPipeline(true, false));
}
render_pass = pre_raster_lib.gp_ci_.renderPass;
subpass = pre_raster_lib.gp_ci_.subpass;
CreatePipelineHelper frag_shader_lib(*this);
{
const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, bindStateFragShaderText);
auto fs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
fs_ci.codeSize = fs_spv.size() * sizeof(decltype(fs_spv)::value_type);
fs_ci.pCode = fs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&fs_ci);
stage_ci.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
auto link_info = LvlInitStruct<VkPipelineLibraryCreateInfoKHR>();
link_info.libraryCount = 1;
link_info.pLibraries = &pre_raster_lib.pipeline_;
frag_shader_lib.InitFragmentLibInfo(1, &stage_ci, &link_info);
frag_shader_lib.InitState();
m_errorMonitor->VerifyNotFound();
frag_shader_lib.gp_ci_.renderPass = render_pass;
frag_shader_lib.gp_ci_.subpass = subpass;
frag_shader_lib.gp_ci_.layout = pipeline_layout_fs.handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-06757");
frag_shader_lib.CreateGraphicsPipeline(true, false);
m_errorMonitor->VerifyFound();
}
}
TEST_F(VkGraphicsLibraryLayerTest, InvalidDSLShaderBindingsLinkOnly) {
TEST_DESCRIPTION("Link pre-raster and FS subsets with invalid null DSL + shader stage bindings");
m_errorMonitor->ExpectSuccess();
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
auto vkGetPhysicalDeviceFeatures2KHR = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
vk::GetInstanceProcAddr(instance(), "vkGetPhysicalDeviceFeatures2KHR"));
ASSERT_TRUE(vkGetPhysicalDeviceFeatures2KHR != nullptr);
auto gpl_features = LvlInitStruct<VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT>();
auto features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>(&gpl_features);
vkGetPhysicalDeviceFeatures2KHR(gpu(), &features2);
if (!gpl_features.graphicsPipelineLibrary) {
GTEST_SKIP() << "VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT::graphicsPipelineLibrary not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
// Prepare descriptors
OneOffDescriptorSet ds(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr},
});
OneOffDescriptorSet ds2(
m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
VkPipelineLayoutObj pipeline_layout_vs(m_device, {&ds.layout_, &ds2.layout_}, {},
VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT);
VkPipelineLayoutObj pipeline_layout_fs(m_device, {&ds.layout_, nullptr}, {},
VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT);
// Layout, renderPass, and subpass all need to be shared across libraries in the same executable pipeline
VkRenderPass render_pass = VK_NULL_HANDLE;
uint32_t subpass = 0;
CreatePipelineHelper pre_raster_lib(*this);
{
const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, bindStateVertShaderText);
auto vs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
vs_ci.codeSize = vs_spv.size() * sizeof(decltype(vs_spv)::value_type);
vs_ci.pCode = vs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&vs_ci);
stage_ci.stage = VK_SHADER_STAGE_VERTEX_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
pre_raster_lib.InitPreRasterLibInfo(1, &stage_ci);
pre_raster_lib.InitState();
pre_raster_lib.gp_ci_.layout = pipeline_layout_vs.handle();
ASSERT_VK_SUCCESS(pre_raster_lib.CreateGraphicsPipeline(true, false));
}
render_pass = pre_raster_lib.gp_ci_.renderPass;
subpass = pre_raster_lib.gp_ci_.subpass;
CreatePipelineHelper frag_shader_lib(*this);
{
const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, bindStateFragShaderText);
auto fs_ci = LvlInitStruct<VkShaderModuleCreateInfo>();
fs_ci.codeSize = fs_spv.size() * sizeof(decltype(fs_spv)::value_type);
fs_ci.pCode = fs_spv.data();
auto stage_ci = LvlInitStruct<VkPipelineShaderStageCreateInfo>(&fs_ci);
stage_ci.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
frag_shader_lib.InitFragmentLibInfo(1, &stage_ci);
frag_shader_lib.InitState();
frag_shader_lib.gp_ci_.renderPass = render_pass;
frag_shader_lib.gp_ci_.subpass = subpass;
frag_shader_lib.gp_ci_.layout = pipeline_layout_fs.handle();
ASSERT_VK_SUCCESS(frag_shader_lib.CreateGraphicsPipeline(true, false));
}
m_errorMonitor->VerifyNotFound();
VkPipeline libraries[2] = {
pre_raster_lib.pipeline_,
frag_shader_lib.pipeline_,
};
auto link_info = LvlInitStruct<VkPipelineLibraryCreateInfoKHR>();
link_info.libraryCount = size(libraries);
link_info.pLibraries = libraries;
auto lib_ci = LvlInitStruct<VkGraphicsPipelineCreateInfo>(&link_info);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-pLibraries-06758");
vk_testing::Pipeline lib(*m_device, lib_ci);
m_errorMonitor->VerifyFound();
}
TEST_F(VkGraphicsLibraryLayerTest, CreateGraphicsPipelineWithMissingMultisampleState) {
TEST_DESCRIPTION("Create pipeline with fragment shader that uses samples, but multisample state not begin set");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (DeviceValidationVersion() < VK_API_VERSION_1_1) {
GTEST_SKIP() << "At least Vulkan version 1.1 is required";
}
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
auto dynamic_rendering_features = LvlInitStruct<VkPhysicalDeviceDynamicRenderingFeatures>();
VkPhysicalDeviceFeatures2 features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>(&dynamic_rendering_features);
vk::GetPhysicalDeviceFeatures2(gpu(), &features2);
if (dynamic_rendering_features.dynamicRendering == VK_FALSE) {
printf("%s Test requires (unsupported) dynamicRendering , skipping\n", kSkipPrefix);
return;
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
CreatePipelineHelper pipe(*this);
pipe.InitInfo();
pipe.gp_ci_.renderPass = VK_NULL_HANDLE;
pipe.gp_ci_.pMultisampleState = nullptr;
pipe.InitState();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-pMultisampleState-06630");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}