blob: 79f16bbaa6636d14439ff32db9d91ccf62c746ad [file] [log] [blame]
/*
* Copyright (c) 2015-2023 The Khronos Group Inc.
* Copyright (c) 2015-2023 Valve Corporation
* Copyright (c) 2015-2023 LunarG, Inc.
* Copyright (c) 2015-2023 Google, Inc.
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
*
* 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 "utils/cast_utils.h"
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
TEST_F(NegativePipeline, NotBound) {
TEST_DESCRIPTION("Pass in an invalid pipeline object handle into a Vulkan API call.");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindPipeline-pipeline-parameter");
RETURN_IF_SKIP(Init())
InitRenderTarget();
VkPipeline badPipeline = CastToHandle<VkPipeline, uintptr_t>(0xbaadb1be);
m_commandBuffer->begin();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, badPipeline);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, WrongBindPointGraphics) {
TEST_DESCRIPTION("Bind a compute pipeline in the graphics bind point");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindPipeline-pipelineBindPoint-00779");
RETURN_IF_SKIP(Init())
InitRenderTarget();
CreateComputePipelineHelper pipe(*this);
pipe.InitState();
pipe.CreateComputePipeline();
m_commandBuffer->begin();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, BasicCompute) {
TEST_DESCRIPTION("Bind a compute pipeline (no subpasses)");
RETURN_IF_SKIP(Init())
const char *cs = R"glsl(#version 450
layout(local_size_x=1) in;
layout(set=0, binding=0) uniform block { vec4 x; };
void main(){
vec4 v = 2.0 * x;
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = std::make_unique<VkShaderObj>(this, cs, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.InitState();
pipe.CreateComputePipeline();
VkBufferCreateInfo bci = vku::InitStructHelper();
bci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
bci.size = 1024;
vkt::Buffer buffer(*m_device, bci);
pipe.descriptor_set_->WriteDescriptorBufferInfo(0, buffer.handle(), 0, 1024);
pipe.descriptor_set_->UpdateDescriptorSets();
m_commandBuffer->begin();
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_.handle(), 0, 1,
&pipe.descriptor_set_->set_, 0, nullptr);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_);
vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1);
}
TEST_F(NegativePipeline, WrongBindPointCompute) {
TEST_DESCRIPTION("Bind a graphics pipeline in the compute bind point");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindPipeline-pipelineBindPoint-00780");
RETURN_IF_SKIP(Init())
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.CreateGraphicsPipeline();
m_commandBuffer->begin();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, DisabledIndependentBlend) {
TEST_DESCRIPTION(
"Generate INDEPENDENT_BLEND by disabling independent blend and then specifying different blend states for two "
"attachments");
VkPhysicalDeviceFeatures features = {};
features.independentBlend = VK_FALSE;
RETURN_IF_SKIP(Init(&features));
VkDescriptorSetObj descriptorSet(m_device);
descriptorSet.AppendDummy();
descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
// Create a renderPass with two color attachments
VkAttachmentReference attachments[2] = {};
attachments[0].layout = VK_IMAGE_LAYOUT_GENERAL;
attachments[1].attachment = 1;
attachments[1].layout = VK_IMAGE_LAYOUT_GENERAL;
VkSubpassDescription subpass = {};
subpass.pColorAttachments = attachments;
subpass.colorAttachmentCount = 2;
VkRenderPassCreateInfo rpci = vku::InitStructHelper();
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
rpci.attachmentCount = 2;
VkAttachmentDescription attach_desc[2] = {};
attach_desc[0].format = VK_FORMAT_B8G8R8A8_UNORM;
attach_desc[0].samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc[0].initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
attach_desc[0].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
attach_desc[1].format = VK_FORMAT_B8G8R8A8_UNORM;
attach_desc[1].samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc[1].initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
attach_desc[1].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
rpci.pAttachments = attach_desc;
vkt::RenderPass renderpass(*m_device, rpci);
ASSERT_TRUE(renderpass.initialized());
CreatePipelineHelper pipe(*this, 2);
pipe.InitState();
pipe.gp_ci_.layout = descriptorSet.GetPipelineLayout();
pipe.gp_ci_.renderPass = renderpass.handle();
pipe.cb_attachments_[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR;
pipe.cb_attachments_[0].blendEnable = VK_TRUE;
pipe.cb_attachments_[1].dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR;
pipe.cb_attachments_[1].blendEnable = VK_FALSE;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, BlendingOnFormatWithoutBlendingSupport) {
TEST_DESCRIPTION("Test that blending is not enabled with a format not support blending");
VkPhysicalDeviceFeatures features = {};
features.independentBlend = VK_FALSE;
RETURN_IF_SKIP(Init(&features));
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06041");
VkFormat non_blending_format = VK_FORMAT_UNDEFINED;
for (uint32_t i = 1; i <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK; i++) {
VkFormatProperties format_props = m_device->format_properties(static_cast<VkFormat>(i));
if ((format_props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) &&
!(format_props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)) {
non_blending_format = static_cast<VkFormat>(i);
break;
}
}
if (non_blending_format == VK_FORMAT_UNDEFINED) {
GTEST_SKIP() << "Unable to find a color attachment format with no blending support";
}
VkDescriptorSetObj descriptorSet(m_device);
descriptorSet.AppendDummy();
descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
// Create a renderPass with two color attachments
VkAttachmentReference attachment = {};
attachment.layout = VK_IMAGE_LAYOUT_GENERAL;
VkSubpassDescription subpass = {};
subpass.pColorAttachments = &attachment;
subpass.colorAttachmentCount = 1;
VkRenderPassCreateInfo rpci = vku::InitStructHelper();
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
rpci.attachmentCount = 1;
VkAttachmentDescription attach_desc = {};
attach_desc.format = non_blending_format;
attach_desc.samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
rpci.pAttachments = &attach_desc;
vkt::RenderPass rp(*m_device, rpci);
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.gp_ci_.layout = descriptorSet.GetPipelineLayout();
pipe.gp_ci_.renderPass = rp.handle();
pipe.cb_attachments_[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR;
pipe.cb_attachments_[0].blendEnable = VK_TRUE;
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
// Is the Pipeline compatible with the expectations of the Renderpass/subpasses?
TEST_F(VkLayerTest, PipelineRenderpassCompatibility) {
TEST_DESCRIPTION(
"Create a graphics pipeline that is incompatible with the requirements of its contained Renderpass/subpasses.");
RETURN_IF_SKIP(Init())
InitRenderTarget();
VkPipelineColorBlendAttachmentState att_state1 = {};
att_state1.dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR;
att_state1.blendEnable = VK_TRUE;
auto set_info = [&](CreatePipelineHelper &helper) {
helper.cb_attachments_[0] = att_state1;
helper.gp_ci_.pColorBlendState = nullptr;
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-09030");
}
TEST_F(VkLayerTest, CmdBufferPipelineDestroyed) {
TEST_DESCRIPTION("Attempt to draw with a command buffer that is invalid due to a pipeline dependency being destroyed.");
RETURN_IF_SKIP(Init())
InitRenderTarget();
{
// Use helper to create graphics pipeline
CreatePipelineHelper helper(*this);
helper.InitState();
helper.CreateGraphicsPipeline();
// Bind helper pipeline to command buffer
m_commandBuffer->begin();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, helper.pipeline_);
m_commandBuffer->end();
// pipeline will be destroyed when helper goes out of scope
}
// Cause error by submitting command buffer that references destroyed pipeline
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "UNASSIGNED-CoreValidation-DrawState-InvalidCommandBuffer-VkPipeline");
m_commandBuffer->QueueCommandBuffer(false);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, BadPipelineObject) {
SetTargetApiVersion(VK_API_VERSION_1_2);
constexpr uint64_t fake_pipeline_handle = 0xbaad6001;
VkPipeline bad_pipeline = CastFromUint64<VkPipeline>(fake_pipeline_handle);
// Enable VK_KHR_draw_indirect_count for KHR variants
AddOptionalExtensions(VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceVulkan12Features features12 = vku::InitStructHelper();
GetPhysicalDeviceFeatures2(features12);
bool has_khr_indirect = IsExtensionsEnabled(VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME);
if (has_khr_indirect && !features12.drawIndirectCount) {
GTEST_SKIP() << VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME << " is enabled, but the drawIndirectCount is not supported.";
}
RETURN_IF_SKIP(InitState(nullptr, &features12));
InitRenderTarget();
// Attempt to bind an invalid Pipeline to a valid Command Buffer
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindPipeline-pipeline-parameter");
m_commandBuffer->begin();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, bad_pipeline);
m_errorMonitor->VerifyFound();
// Try each of the 6 flavors of Draw()
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); // Draw*() calls must be submitted within a renderpass
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-None-08606");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
vkt::Buffer index_buffer(*m_device, 1024, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), index_buffer.handle(), 2, VK_INDEX_TYPE_UINT16);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndexed-None-08606");
vk::CmdDrawIndexed(m_commandBuffer->handle(), 1, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
VkBufferCreateInfo ci = vku::InitStructHelper();
ci.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
ci.size = 1024;
vkt::Buffer buffer(*m_device, ci);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndirect-None-08606");
vk::CmdDrawIndirect(m_commandBuffer->handle(), buffer.handle(), 0, 1, 0);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndexedIndirect-None-08606");
vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), buffer.handle(), 0, 1, 0);
m_errorMonitor->VerifyFound();
if (has_khr_indirect) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndirectCount-None-08606");
// stride must be a multiple of 4 and must be greater than or equal to sizeof(VkDrawIndirectCommand)
vk::CmdDrawIndirectCountKHR(m_commandBuffer->handle(), buffer.handle(), 0, buffer.handle(), 512, 1, 512);
m_errorMonitor->VerifyFound();
if (DeviceValidationVersion() >= VK_API_VERSION_1_2) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndirectCount-None-08606");
// stride must be a multiple of 4 and must be greater than or equal to sizeof(VkDrawIndirectCommand)
vk::CmdDrawIndirectCount(m_commandBuffer->handle(), buffer.handle(), 0, buffer.handle(), 512, 1, 512);
m_errorMonitor->VerifyFound();
}
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndexedIndirectCount-None-08606");
// stride must be a multiple of 4 and must be greater than or equal to sizeof(VkDrawIndexedIndirectCommand)
vk::CmdDrawIndexedIndirectCountKHR(m_commandBuffer->handle(), buffer.handle(), 0, buffer.handle(), 512, 1, 512);
m_errorMonitor->VerifyFound();
if (DeviceValidationVersion() >= VK_API_VERSION_1_2) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndexedIndirectCount-None-08606");
// stride must be a multiple of 4 and must be greater than or equal to sizeof(VkDrawIndexedIndirectCommand)
vk::CmdDrawIndexedIndirectCount(m_commandBuffer->handle(), buffer.handle(), 0, buffer.handle(), 512, 1, 512);
m_errorMonitor->VerifyFound();
}
}
// Also try the Dispatch variants
m_commandBuffer->EndRenderPass(); // Compute submissions must be outside a renderpass
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDispatch-None-08606");
vk::CmdDispatch(m_commandBuffer->handle(), 0, 0, 0);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDispatchIndirect-None-08606");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDispatchIndirect-offset-00407");
vk::CmdDispatchIndirect(m_commandBuffer->handle(), buffer.handle(), ci.size);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, ShaderStageName) {
TEST_DESCRIPTION("Create Pipelines with invalid state set");
RETURN_IF_SKIP(Init())
InitRenderTarget();
VkShaderObj vs(this, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(this, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
// Attempt to Create Gfx Pipeline w/o a VS
VkPipelineShaderStageCreateInfo shaderStage = fs.GetStageCreateInfo(); // should be: vs.GetStageCreateInfo();
auto set_info = [&](CreatePipelineHelper &helper) { helper.shader_stages_ = {shaderStage}; };
constexpr std::array vuids = {"VUID-VkGraphicsPipelineCreateInfo-pStages-06896",
"VUID-VkGraphicsPipelineCreateInfo-stage-02096"};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, vuids);
// Finally, check the string validation for the shader stage pName variable. Correct the shader stage data, and bork the
// string before calling again
shaderStage = vs.GetStageCreateInfo();
const uint8_t cont_char = 0xf8;
char bad_string[] = {static_cast<char>(cont_char), static_cast<char>(cont_char), static_cast<char>(cont_char),
static_cast<char>(cont_char)};
shaderStage.pName = bad_string;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "contains invalid characters or is badly formed");
}
TEST_F(NegativePipeline, ShaderStageBit) {
TEST_DESCRIPTION("Create Pipelines with invalid state set");
RETURN_IF_SKIP(Init())
InitRenderTarget();
// Make sure compute pipeline has a compute shader stage set
char const *csSource = R"glsl(
#version 450
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
void main(){
if (gl_GlobalInvocationID.x >= 0) { return; }
}
)glsl";
CreateComputePipelineHelper cs_pipeline(*this);
cs_pipeline.cs_ = std::make_unique<VkShaderObj>(this, csSource, VK_SHADER_STAGE_COMPUTE_BIT);
cs_pipeline.InitState();
cs_pipeline.pipeline_layout_ = vkt::PipelineLayout(*m_device, {});
cs_pipeline.LateBindPipelineInfo();
cs_pipeline.cp_ci_.stage.stage = VK_SHADER_STAGE_VERTEX_BIT; // override with wrong value
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkComputePipelineCreateInfo-stage-00701");
cs_pipeline.CreateComputePipeline(false); // need false to prevent late binding
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, SampleRateFeatureDisable) {
// Enable sample shading in pipeline when the feature is disabled.
// Disable sampleRateShading here
VkPhysicalDeviceFeatures device_features = {};
device_features.sampleRateShading = VK_FALSE;
RETURN_IF_SKIP(Init(&device_features));
InitRenderTarget();
// Cause the error by enabling sample shading...
auto set_shading_enable = [](CreatePipelineHelper &helper) { helper.pipe_ms_state_ci_.sampleShadingEnable = VK_TRUE; };
CreatePipelineHelper::OneshotTest(*this, set_shading_enable, kErrorBit,
"VUID-VkPipelineMultisampleStateCreateInfo-sampleShadingEnable-00784");
}
TEST_F(NegativePipeline, SampleRateFeatureEnable) {
// Enable sample shading in pipeline when the feature is disabled.
RETURN_IF_SKIP(InitFramework())
// Require sampleRateShading here
VkPhysicalDeviceFeatures device_features = {};
GetPhysicalDeviceFeatures(&device_features);
if (device_features.sampleRateShading == VK_FALSE) {
GTEST_SKIP() << "SampleRateShading feature is disabled";
}
RETURN_IF_SKIP(InitState(&device_features));
InitRenderTarget();
auto range_test = [this](float value, bool positive_test) {
auto info_override = [value](CreatePipelineHelper &helper) {
helper.pipe_ms_state_ci_.sampleShadingEnable = VK_TRUE;
helper.pipe_ms_state_ci_.minSampleShading = value;
};
if (positive_test) {
CreatePipelineHelper::OneshotTest(*this, info_override, kErrorBit);
} else {
CreatePipelineHelper::OneshotTest(*this, info_override, kErrorBit,
"VUID-VkPipelineMultisampleStateCreateInfo-minSampleShading-00786");
}
};
range_test(NearestSmaller(0.0F), false);
range_test(NearestGreater(1.0F), false);
range_test(0.0F, /* positive_test= */ true);
range_test(1.0F, /* positive_test= */ true);
}
TEST_F(NegativePipeline, DepthClipControlFeatureDisable) {
// Enable negativeOneToOne (VK_EXT_depth_clip_control) in pipeline when the feature is disabled.
RETURN_IF_SKIP(Init())
InitRenderTarget();
VkPipelineViewportDepthClipControlCreateInfoEXT clip_control = vku::InitStructHelper();
clip_control.negativeOneToOne = VK_TRUE;
auto set_shading_enable = [clip_control](CreatePipelineHelper &helper) { helper.vp_state_ci_.pNext = &clip_control; };
CreatePipelineHelper::OneshotTest(*this, set_shading_enable, kErrorBit,
"VUID-VkPipelineViewportDepthClipControlCreateInfoEXT-negativeOneToOne-06470");
}
TEST_F(NegativePipeline, SamplePNextUnknown) {
TEST_DESCRIPTION("Pass unknown pNext into VkPipelineMultisampleStateCreateInfo");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME);
RETURN_IF_SKIP(Init())
InitRenderTarget();
VkPipelineSampleLocationsStateCreateInfoEXT sample_locations = vku::InitStructHelper();
sample_locations.sampleLocationsInfo = vku::InitStructHelper();
auto good_chain = [&sample_locations](CreatePipelineHelper &helper) { helper.pipe_ms_state_ci_.pNext = &sample_locations; };
CreatePipelineHelper::OneshotTest(*this, good_chain, kErrorBit);
VkInstanceCreateInfo instance_ci = vku::InitStructHelper();
auto bad_chain = [&instance_ci](CreatePipelineHelper &helper) { helper.pipe_ms_state_ci_.pNext = &instance_ci; };
CreatePipelineHelper::OneshotTest(*this, bad_chain, kErrorBit, "VUID-VkPipelineMultisampleStateCreateInfo-pNext-pNext");
}
// TODO 5600 - Not all pNext structs are being passed in to check extensions
TEST_F(NegativePipeline, DISABLED_SamplePNextDisabled) {
TEST_DESCRIPTION("Pass valid pNext VkPipelineMultisampleStateCreateInfo, but without extension enabled");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
RETURN_IF_SKIP(Init())
InitRenderTarget();
VkPipelineSampleLocationsStateCreateInfoEXT sample_locations = vku::InitStructHelper();
sample_locations.sampleLocationsInfo = vku::InitStructHelper();
auto bad_chain = [&sample_locations](CreatePipelineHelper &helper) { helper.pipe_ms_state_ci_.pNext = &sample_locations; };
CreatePipelineHelper::OneshotTest(*this, bad_chain, kErrorBit, "VUID-VkPipelineMultisampleStateCreateInfo-pNext-pNext");
}
TEST_F(NegativePipeline, SubpassRasterizationSamples) {
TEST_DESCRIPTION("Test creating two pipelines referring to the same subpass but with different rasterization samples count");
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceFeatures device_features = {};
device_features.variableMultisampleRate = VK_FALSE;
RETURN_IF_SKIP(InitState(&device_features));
InitRenderTarget();
// Create a render pass with 1 subpass. This subpass uses no attachment.
std::array<VkAttachmentReference, 1> attachmentRefs = {};
attachmentRefs[0].layout = VK_IMAGE_LAYOUT_GENERAL;
attachmentRefs[0].attachment = VK_ATTACHMENT_UNUSED;
VkSubpassDescription subpass = {};
subpass.flags = VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = attachmentRefs.data();
VkAttachmentDescription attach_desc = {};
attach_desc.format = m_renderTargets[0]->format();
attach_desc.samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attach_desc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkRenderPassCreateInfo rpci = vku::InitStructHelper();
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
rpci.attachmentCount = 1;
rpci.pAttachments = &attach_desc;
vkt::RenderPass renderpass(*m_device, rpci);
ASSERT_TRUE(renderpass.initialized());
auto render_target_view = m_renderTargets[0]->targetView(m_renderTargets[0]->format());
VkFramebufferCreateInfo framebuffer_info = vku::InitStructHelper();
framebuffer_info.renderPass = renderpass;
framebuffer_info.width = m_renderTargets[0]->width();
framebuffer_info.height = m_renderTargets[0]->height();
framebuffer_info.layers = 1;
framebuffer_info.attachmentCount = 1;
framebuffer_info.pAttachments = &render_target_view;
vkt::Framebuffer framebuffer(*m_device, framebuffer_info);
VkDescriptorSetObj descriptorSet(m_device);
descriptorSet.AppendDummy();
descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
CreatePipelineHelper pipeline_1(*this);
pipeline_1.InitState();
pipeline_1.pipe_ms_state_ci_.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
pipeline_1.gp_ci_.layout = descriptorSet.GetPipelineLayout();
pipeline_1.gp_ci_.renderPass = renderpass.handle();
pipeline_1.CreateGraphicsPipeline();
CreatePipelineHelper pipeline_2(*this);
pipeline_2.InitState();
pipeline_2.pipe_ms_state_ci_.rasterizationSamples = VK_SAMPLE_COUNT_4_BIT;
pipeline_2.gp_ci_.layout = descriptorSet.GetPipelineLayout();
pipeline_2.gp_ci_.renderPass = renderpass.handle();
pipeline_2.CreateGraphicsPipeline();
VkRenderPassBeginInfo rpbinfo = vku::InitStructHelper();
rpbinfo.renderPass = renderpass.handle();
rpbinfo.framebuffer = framebuffer;
rpbinfo.renderArea.extent.width = framebuffer_info.width;
rpbinfo.renderArea.extent.height = framebuffer_info.height;
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(rpbinfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_1.Handle());
// VkPhysicalDeviceFeatures::variableMultisampleRate is false,
// the two pipelines refer to the same subpass, one that does not use any attachment,
// BUT the secondly created pipeline has a different sample samples count than the 1st, this is illegal
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-subpass-00758");
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_2.Handle());
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
TEST_F(NegativePipeline, RenderPassShaderResolveQCOM) {
TEST_DESCRIPTION("Test pipeline creation VUIDs added with VK_QCOM_render_pass_shader_resolve extension.");
AddRequiredExtensions(VK_QCOM_RENDER_PASS_SHADER_RESOLVE_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
// Require sampleRateShading for these tests
VkPhysicalDeviceFeatures device_features = {};
GetPhysicalDeviceFeatures(&device_features);
if (device_features.sampleRateShading == VK_FALSE) {
GTEST_SKIP() << "SampleRateShading feature is disabled -- skipping related checks.";
}
RETURN_IF_SKIP(InitState(&device_features));
InitRenderTarget();
VkDescriptorSetObj descriptorSet(m_device);
descriptorSet.AppendDummy();
descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
// Create a renderPass with two attachments (0=Color, 1=Input)
VkAttachmentReference attachmentRefs[2] = {};
attachmentRefs[0].layout = VK_IMAGE_LAYOUT_GENERAL;
attachmentRefs[0].attachment = 0;
attachmentRefs[1].layout = VK_IMAGE_LAYOUT_GENERAL;
attachmentRefs[1].attachment = 1;
VkSubpassDescription subpass = {};
subpass.flags = VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &attachmentRefs[0];
subpass.inputAttachmentCount = 1;
subpass.pInputAttachments = &attachmentRefs[1];
VkRenderPassCreateInfo rpci = vku::InitStructHelper();
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
rpci.attachmentCount = 2;
VkAttachmentDescription attach_desc[2] = {};
attach_desc[0].format = VK_FORMAT_B8G8R8A8_UNORM;
attach_desc[0].samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attach_desc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attach_desc[0].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
attach_desc[1].format = VK_FORMAT_B8G8R8A8_UNORM;
attach_desc[1].samples = VK_SAMPLE_COUNT_4_BIT;
attach_desc[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attach_desc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attach_desc[1].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
rpci.pAttachments = attach_desc;
// renderpass has 1xMSAA colorAttachent and 4xMSAA inputAttachment
vkt::RenderPass renderpass(*m_device, rpci);
ASSERT_TRUE(renderpass.initialized());
// renderpass2 has 1xMSAA colorAttachent and 1xMSAA inputAttachment
attach_desc[1].samples = VK_SAMPLE_COUNT_1_BIT;
vkt::RenderPass renderpass2(*m_device, rpci);
ASSERT_TRUE(renderpass2.initialized());
// shader uses gl_SamplePosition which causes the SPIR-V to include SampleRateShading capability
static const char *sampleRateFragShaderText = R"glsl(
#version 450
layout(location = 0) out vec4 uFragColor;
void main() {
uFragColor = vec4(gl_SamplePosition.x,1,0,1);
}
)glsl";
VkShaderObj fs_sampleRate(this, sampleRateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineMultisampleStateCreateInfo ms_state = vku::InitStructHelper();
ms_state.flags = 0;
ms_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
ms_state.sampleShadingEnable = VK_FALSE;
ms_state.minSampleShading = 0.0f;
ms_state.pSampleMask = nullptr;
ms_state.alphaToCoverageEnable = VK_FALSE;
ms_state.alphaToOneEnable = VK_FALSE;
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.gp_ci_.layout = descriptorSet.GetPipelineLayout();
pipe.gp_ci_.renderPass = renderpass.handle();
pipe.cb_attachments_[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR;
pipe.cb_attachments_[0].blendEnable = VK_TRUE;
pipe.gp_ci_.pMultisampleState = &ms_state;
// Create a pipeline with a subpass using VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM,
// but where sample count of input attachment doesnt match rasterizationSamples
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-rasterizationSamples-04899");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
ms_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
ms_state.sampleShadingEnable = VK_TRUE;
pipe.gp_ci_.renderPass = renderpass2.handle();
// Create a pipeline with a subpass using VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM,
// and with sampleShadingEnable enabled in the pipeline
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-sampleShadingEnable-04900");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
ms_state.sampleShadingEnable = VK_FALSE;
pipe.shader_stages_[1] = fs_sampleRate.GetStageCreateInfo();
// Create a pipeline with a subpass using VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM,
// and with SampleRateShading capability enabled in the SPIR-V fragment shader
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-RuntimeSpirv-SampleRateShading-06378");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, RasterizerDiscardWithFragmentShader) {
TEST_DESCRIPTION("Create Graphics Pipeline with fragment shader and rasterizer discard");
RETURN_IF_SKIP(Init())
m_depth_stencil_fmt = FindSupportedDepthStencilFormat(gpu());
m_depthStencil->Init(m_width, m_height, 1, m_depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
VK_IMAGE_TILING_OPTIMAL);
VkImageView depth_image_view =
m_depthStencil->targetView(m_depth_stencil_fmt, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
InitRenderTarget(&depth_image_view);
VkShaderObj vs(this, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(this, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
const VkPipelineShaderStageCreateInfo stages[] = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
const VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, nullptr, 0, 0, nullptr, 0, nullptr};
const VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE};
const VkPipelineRasterizationStateCreateInfo pipeline_rasterization_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
nullptr,
0,
VK_FALSE,
VK_TRUE,
VK_POLYGON_MODE_FILL,
VK_CULL_MODE_NONE,
VK_FRONT_FACE_COUNTER_CLOCKWISE,
VK_FALSE,
0.0f,
0.0f,
0.0f,
1.0f};
VkPipelineLayout pipeline_layout;
VkPipelineLayoutCreateInfo pipeline_layout_create_info = vku::InitStructHelper();
VkResult err = vk::CreatePipelineLayout(m_device->device(), &pipeline_layout_create_info, nullptr, &pipeline_layout);
ASSERT_EQ(VK_SUCCESS, err);
VkGraphicsPipelineCreateInfo graphics_pipeline_create_info{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
nullptr,
0,
2,
stages,
&pipeline_vertex_input_state_create_info,
&pipeline_input_assembly_state_create_info,
nullptr,
nullptr,
&pipeline_rasterization_state_create_info,
nullptr,
nullptr,
nullptr,
nullptr,
pipeline_layout,
m_renderPass,
0,
VK_NULL_HANDLE,
-1};
VkPipeline pipeline;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-pStages-06894");
vk::CreateGraphicsPipelines(m_device->handle(), VK_NULL_HANDLE, 1, &graphics_pipeline_create_info, nullptr, &pipeline);
m_errorMonitor->VerifyFound();
vk::DestroyPipelineLayout(m_device->handle(), pipeline_layout, nullptr);
}
TEST_F(NegativePipeline, CreateGraphicsPipelineWithBadBasePointer) {
TEST_DESCRIPTION("Create Graphics Pipeline with pointers that must be ignored by layers");
RETURN_IF_SKIP(Init())
m_depth_stencil_fmt = FindSupportedDepthStencilFormat(gpu());
m_depthStencil->Init(m_width, m_height, 1, m_depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
VK_IMAGE_TILING_OPTIMAL);
VkImageView depth_image_view =
m_depthStencil->targetView(m_depth_stencil_fmt, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
InitRenderTarget(&depth_image_view);
VkShaderObj vs(this, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
const VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, nullptr, 0, 0, nullptr, 0, nullptr};
const VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE};
const VkPipelineRasterizationStateCreateInfo pipeline_rasterization_state_create_info_template{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
nullptr,
0,
VK_FALSE,
VK_FALSE,
VK_POLYGON_MODE_FILL,
VK_CULL_MODE_NONE,
VK_FRONT_FACE_COUNTER_CLOCKWISE,
VK_FALSE,
0.0f,
0.0f,
0.0f,
1.0f};
VkPipelineLayout pipeline_layout;
VkPipelineLayoutCreateInfo pipeline_layout_create_info = vku::InitStructHelper();
VkResult err = vk::CreatePipelineLayout(m_device->device(), &pipeline_layout_create_info, nullptr, &pipeline_layout);
ASSERT_EQ(VK_SUCCESS, err);
VkPipelineRasterizationStateCreateInfo pipeline_rasterization_state_create_info =
pipeline_rasterization_state_create_info_template;
pipeline_rasterization_state_create_info.rasterizerDiscardEnable = VK_TRUE;
constexpr uint64_t fake_pipeline_id = 0xCADECADE;
VkPipeline fake_pipeline_handle = CastFromUint64<VkPipeline>(fake_pipeline_id);
VkGraphicsPipelineCreateInfo graphics_pipeline_create_info{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
nullptr,
VK_PIPELINE_CREATE_DERIVATIVE_BIT,
1,
&vs.GetStageCreateInfo(),
&pipeline_vertex_input_state_create_info,
&pipeline_input_assembly_state_create_info,
nullptr,
nullptr,
&pipeline_rasterization_state_create_info,
nullptr,
nullptr,
nullptr,
nullptr,
pipeline_layout,
m_renderPass,
0,
fake_pipeline_handle,
-1};
VkPipeline pipeline;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-07984");
vk::CreateGraphicsPipelines(m_device->handle(), VK_NULL_HANDLE, 1, &graphics_pipeline_create_info, nullptr, &pipeline);
m_errorMonitor->VerifyFound();
graphics_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
graphics_pipeline_create_info.basePipelineIndex = 6;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-07985");
vk::CreateGraphicsPipelines(m_device->handle(), VK_NULL_HANDLE, 1, &graphics_pipeline_create_info, nullptr, &pipeline);
m_errorMonitor->VerifyFound();
vk::DestroyPipelineLayout(m_device->handle(), pipeline_layout, nullptr);
}
TEST_F(NegativePipeline, PipelineCreationCacheControl) {
TEST_DESCRIPTION("Test VK_EXT_pipeline_creation_cache_control");
AddRequiredExtensions(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT cache_control_features = vku::InitStructHelper();
cache_control_features.pipelineCreationCacheControl = VK_FALSE; // Tests all assume feature is off
RETURN_IF_SKIP(InitState(nullptr, &cache_control_features));
InitRenderTarget();
const auto set_graphics_flags = [&](CreatePipelineHelper &helper) {
helper.gp_ci_.flags = VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT;
};
CreatePipelineHelper::OneshotTest(*this, set_graphics_flags, kErrorBit,
"VUID-VkGraphicsPipelineCreateInfo-pipelineCreationCacheControl-02878");
const auto set_compute_flags = [&](CreateComputePipelineHelper &helper) {
helper.cp_ci_.flags = VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT;
};
CreateComputePipelineHelper::OneshotTest(*this, set_compute_flags, kErrorBit,
"VUID-VkComputePipelineCreateInfo-pipelineCreationCacheControl-02875");
VkPipelineCache pipeline_cache;
VkPipelineCacheCreateInfo cache_create_info = vku::InitStructHelper();
cache_create_info.initialDataSize = 0;
cache_create_info.flags = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineCacheCreateInfo-pipelineCreationCacheControl-02892");
vk::CreatePipelineCache(m_device->device(), &cache_create_info, nullptr, &pipeline_cache);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, NumSamplesMismatch) {
// Create CommandBuffer where MSAA samples doesn't match RenderPass
// sampleCount
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-multisampledRenderToSingleSampled-07284");
RETURN_IF_SKIP(Init())
InitRenderTarget();
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
VkPipelineMultisampleStateCreateInfo pipe_ms_state_ci = vku::InitStructHelper();
pipe_ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_4_BIT;
pipe_ms_state_ci.sampleShadingEnable = 0;
pipe_ms_state_ci.minSampleShading = 1.0;
pipe_ms_state_ci.pSampleMask = NULL;
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.gp_ci_.layout = pipeline_layout.handle();
pipe.pipe_ms_state_ci_ = pipe_ms_state_ci;
m_errorMonitor->SetUnexpectedError("VUID-VkGraphicsPipelineCreateInfo-multisampledRenderToSingleSampled-06853");
pipe.CreateGraphicsPipeline();
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle());
// Render triangle (the error should trigger on the attempt to draw).
vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0);
// Finalize recording of the command buffer
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, NumBlendAttachMismatch) {
// Create Pipeline where the number of blend attachments doesn't match the
// number of color attachments. In this case, we don't add any color
// blend attachments even though we have a color attachment.
AddOptionalExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
RETURN_IF_SKIP(Init())
InitRenderTarget();
VkPipelineMultisampleStateCreateInfo pipe_ms_state_ci = vku::InitStructHelper();
pipe_ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
pipe_ms_state_ci.sampleShadingEnable = 0;
pipe_ms_state_ci.minSampleShading = 1.0;
pipe_ms_state_ci.pSampleMask = NULL;
const auto set_MSAA = [&](CreatePipelineHelper &helper) {
helper.pipe_ms_state_ci_ = pipe_ms_state_ci;
helper.cb_ci_.attachmentCount = 0;
};
CreatePipelineHelper::OneshotTest(*this, set_MSAA, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-07609");
}
TEST_F(NegativePipeline, ColorBlendInvalidLogicOp) {
TEST_DESCRIPTION("Attempt to use invalid VkPipelineColorBlendStateCreateInfo::logicOp value.");
RETURN_IF_SKIP(Init()) // enables all supported features
InitRenderTarget();
if (!m_device->phy().features().logicOp) {
GTEST_SKIP() << "Device does not support logicOp feature";
}
const auto set_shading_enable = [](CreatePipelineHelper &helper) {
helper.cb_ci_.logicOpEnable = VK_TRUE;
helper.cb_ci_.logicOp = static_cast<VkLogicOp>(VK_LOGIC_OP_SET + 1); // invalid logicOp to be tested
};
CreatePipelineHelper::OneshotTest(*this, set_shading_enable, kErrorBit,
"VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00607");
}
TEST_F(NegativePipeline, ColorBlendUnsupportedLogicOp) {
TEST_DESCRIPTION("Attempt enabling VkPipelineColorBlendStateCreateInfo::logicOpEnable when logicOp feature is disabled.");
VkPhysicalDeviceFeatures features{};
RETURN_IF_SKIP(Init(&features));
InitRenderTarget();
const auto set_shading_enable = [](CreatePipelineHelper &helper) { helper.cb_ci_.logicOpEnable = VK_TRUE; };
CreatePipelineHelper::OneshotTest(*this, set_shading_enable, kErrorBit,
"VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00606");
}
TEST_F(NegativePipeline, ColorBlendUnsupportedDualSourceBlend) {
TEST_DESCRIPTION("Attempt to use dual-source blending when dualSrcBlend feature is disabled.");
VkPhysicalDeviceFeatures features{};
RETURN_IF_SKIP(Init(&features));
InitRenderTarget();
VkPipelineColorBlendAttachmentState cb_attachments = {};
const auto set_dsb_src_color_enable = [&](CreatePipelineHelper &helper) { helper.cb_attachments_[0] = cb_attachments; };
cb_attachments.blendEnable = VK_TRUE;
cb_attachments.srcColorBlendFactor = VK_BLEND_FACTOR_SRC1_COLOR; // bad!
cb_attachments.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
cb_attachments.colorBlendOp = VK_BLEND_OP_ADD;
cb_attachments.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
cb_attachments.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
cb_attachments.alphaBlendOp = VK_BLEND_OP_ADD;
CreatePipelineHelper::OneshotTest(*this, set_dsb_src_color_enable, kErrorBit,
"VUID-VkPipelineColorBlendAttachmentState-srcColorBlendFactor-00608");
cb_attachments.blendEnable = VK_TRUE;
cb_attachments.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR;
cb_attachments.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR; // bad
cb_attachments.colorBlendOp = VK_BLEND_OP_ADD;
cb_attachments.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
cb_attachments.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
cb_attachments.alphaBlendOp = VK_BLEND_OP_ADD;
CreatePipelineHelper::OneshotTest(*this, set_dsb_src_color_enable, kErrorBit,
"VUID-VkPipelineColorBlendAttachmentState-dstColorBlendFactor-00609");
cb_attachments.blendEnable = VK_TRUE;
cb_attachments.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR;
cb_attachments.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
cb_attachments.colorBlendOp = VK_BLEND_OP_ADD;
cb_attachments.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC1_ALPHA; // bad
cb_attachments.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
cb_attachments.alphaBlendOp = VK_BLEND_OP_ADD;
CreatePipelineHelper::OneshotTest(*this, set_dsb_src_color_enable, kErrorBit,
"VUID-VkPipelineColorBlendAttachmentState-srcAlphaBlendFactor-00610");
cb_attachments.blendEnable = VK_TRUE;
cb_attachments.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR;
cb_attachments.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
cb_attachments.colorBlendOp = VK_BLEND_OP_ADD;
cb_attachments.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
cb_attachments.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; // bad!
cb_attachments.alphaBlendOp = VK_BLEND_OP_ADD;
CreatePipelineHelper::OneshotTest(*this, set_dsb_src_color_enable, kErrorBit,
"VUID-VkPipelineColorBlendAttachmentState-dstAlphaBlendFactor-00611");
}
TEST_F(NegativePipeline, DuplicateStage) {
TEST_DESCRIPTION("Test that an error is produced for a pipeline containing multiple shaders for the same stage");
RETURN_IF_SKIP(Init())
InitRenderTarget();
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), helper.vs_->GetStageCreateInfo(),
helper.fs_->GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-stage-06897");
}
TEST_F(NegativePipeline, MissingEntrypoint) {
RETURN_IF_SKIP(Init())
InitRenderTarget();
// Graphics
{
VkShaderObj fs(this, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr,
"foo");
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-pName-00707");
}
// Compute
{
const auto set_info = [&](CreateComputePipelineHelper &helper) {
helper.cs_ = std::make_unique<VkShaderObj>(this, kMinimalShaderGlsl, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0,
SPV_SOURCE_GLSL, nullptr, "foo");
};
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-pName-00707");
}
// Multiple pipeline, middle has missing entrypoint
{
CreateComputePipelineHelper pipe_0(*this); // valid
pipe_0.InitState();
pipe_0.LateBindPipelineInfo();
CreateComputePipelineHelper pipe_1(*this); // invalid
pipe_1.cs_ = std::make_unique<VkShaderObj>(this, kMinimalShaderGlsl, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0,
SPV_SOURCE_GLSL, nullptr, "foo");
pipe_1.InitState();
pipe_1.LateBindPipelineInfo();
VkComputePipelineCreateInfo create_infos[3] = {pipe_0.cp_ci_, pipe_1.cp_ci_, pipe_0.cp_ci_};
VkPipeline pipelines[3];
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-pName-00707");
vk::CreateComputePipelines(m_device->device(), VK_NULL_HANDLE, 3, create_infos, nullptr, pipelines);
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativePipeline, DepthStencilRequired) {
m_errorMonitor->SetDesiredFailureMsg(
kErrorBit, "pDepthStencilState is NULL when rasterization is enabled and subpass uses a depth/stencil attachment");
RETURN_IF_SKIP(Init())
InitRenderTarget();
VkDescriptorSetObj descriptorSet(m_device);
descriptorSet.AppendDummy();
descriptorSet.CreateVKDescriptorSet(m_commandBuffer);
VkAttachmentDescription attachments[] = {
{
0,
VK_FORMAT_B8G8R8A8_UNORM,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
},
{
0,
VK_FORMAT_D16_UNORM,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
},
};
VkAttachmentReference refs[] = {
{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
{1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL},
};
VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &refs[0], nullptr, &refs[1], 0, nullptr};
VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 2, attachments, 1, &subpass, 0, nullptr};
vkt::RenderPass rp(*m_device, rpci);
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.gp_ci_.layout = descriptorSet.GetPipelineLayout();
pipe.gp_ci_.renderPass = rp.handle();
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, NullStagepName) {
TEST_DESCRIPTION("Test that an error is produced for a stage with a null pName pointer");
RETURN_IF_SKIP(Init())
VkShaderObj vs(this, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo()};
pipe.shader_stages_[0].pName = nullptr;
pipe.InitState();
pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {});
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-pName-parameter");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, AMDMixedAttachmentSamplesValidateGraphicsPipeline) {
TEST_DESCRIPTION("Verify an error message for an incorrect graphics pipeline rasterization sample count.");
AddRequiredExtensions(VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
// Set a mismatched sample count
VkPipelineMultisampleStateCreateInfo ms_state_ci = vku::InitStructHelper();
ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_4_BIT;
const auto set_info = [&](CreatePipelineHelper &helper) { helper.pipe_ms_state_ci_ = ms_state_ci; };
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-subpass-01505");
}
TEST_F(NegativePipeline, FramebufferMixedSamplesNV) {
TEST_DESCRIPTION("Verify VK_NV_framebuffer_mixed_samples.");
AddRequiredExtensions(VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceFeatures device_features = {};
GetPhysicalDeviceFeatures(&device_features);
if (VK_TRUE != device_features.sampleRateShading) {
GTEST_SKIP() << "Test requires unsupported sampleRateShading feature";
}
RETURN_IF_SKIP(InitState())
InitRenderTarget();
struct TestCase {
VkSampleCountFlagBits color_samples;
VkSampleCountFlagBits depth_samples;
VkSampleCountFlagBits raster_samples;
VkBool32 depth_test;
VkBool32 sample_shading;
uint32_t table_count;
bool positiveTest;
std::string vuid;
};
std::vector<TestCase> test_cases = {
{VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_FALSE, VK_FALSE, 1, true,
"VUID-VkGraphicsPipelineCreateInfo-multisampledRenderToSingleSampled-06853"},
{VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT, VK_FALSE, VK_FALSE, 4, false,
"VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationTableEnable-01405"},
{VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT, VK_FALSE, VK_FALSE, 2, true,
"VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationTableEnable-01405"},
{VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT, VK_TRUE, VK_FALSE, 1, false,
"VUID-VkGraphicsPipelineCreateInfo-subpass-01411"},
{VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_8_BIT, VK_TRUE, VK_FALSE, 1, true,
"VUID-VkGraphicsPipelineCreateInfo-subpass-01411"},
{VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT, VK_FALSE, VK_FALSE, 1, false,
"VUID-VkGraphicsPipelineCreateInfo-subpass-01412"},
{VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT, VK_FALSE, VK_FALSE, 1, true,
"VUID-VkGraphicsPipelineCreateInfo-subpass-01412"},
{VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_FALSE, VK_TRUE, 1, false,
"VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-01415"},
{VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_FALSE, VK_FALSE, 1, true,
"VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-01415"},
{VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT, VK_FALSE, VK_FALSE, 1, true,
"VUID-VkGraphicsPipelineCreateInfo-multisampledRenderToSingleSampled-06853"}};
for (const auto &test_case : test_cases) {
VkAttachmentDescription att[2] = {{}, {}};
att[0].format = VK_FORMAT_R8G8B8A8_UNORM;
att[0].samples = test_case.color_samples;
att[0].initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
att[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
att[1].format = VK_FORMAT_D24_UNORM_S8_UINT;
att[1].samples = test_case.depth_samples;
att[1].initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
att[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference cr = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
VkAttachmentReference dr = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
VkSubpassDescription sp = {};
sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
sp.colorAttachmentCount = 1;
sp.pColorAttachments = &cr;
sp.pResolveAttachments = NULL;
sp.pDepthStencilAttachment = &dr;
VkRenderPassCreateInfo rpi = vku::InitStructHelper();
rpi.attachmentCount = 2;
rpi.pAttachments = att;
rpi.subpassCount = 1;
rpi.pSubpasses = &sp;
vkt::RenderPass rp(*m_device, rpi);
VkPipelineDepthStencilStateCreateInfo ds = vku::InitStructHelper();
VkPipelineCoverageModulationStateCreateInfoNV cmi = vku::InitStructHelper();
// Create a dummy modulation table that can be used for the positive
// coverageModulationTableCount test.
std::vector<float> cm_table{};
const auto break_samples = [&cmi, &rp, &ds, &cm_table, &test_case](CreatePipelineHelper &helper) {
cm_table.resize(test_case.table_count);
cmi.flags = 0;
cmi.coverageModulationTableEnable = (test_case.table_count > 1);
cmi.coverageModulationTableCount = test_case.table_count;
cmi.pCoverageModulationTable = cm_table.data();
ds.depthTestEnable = test_case.depth_test;
helper.pipe_ms_state_ci_.pNext = &cmi;
helper.pipe_ms_state_ci_.rasterizationSamples = test_case.raster_samples;
helper.pipe_ms_state_ci_.sampleShadingEnable = test_case.sample_shading;
helper.gp_ci_.renderPass = rp.handle();
helper.gp_ci_.pDepthStencilState = &ds;
};
if (!test_case.positiveTest) {
CreatePipelineHelper::OneshotTest(*this, break_samples, kErrorBit, test_case.vuid);
} else {
CreatePipelineHelper::OneshotTest(*this, break_samples, kErrorBit);
}
}
}
TEST_F(NegativePipeline, FramebufferMixedSamples) {
TEST_DESCRIPTION("Verify that the expected VUIds are hits when VK_NV_framebuffer_mixed_samples is disabled.");
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
const VkFormat ds_format = FindSupportedDepthStencilFormat(gpu());
struct TestCase {
VkSampleCountFlagBits color_samples;
VkSampleCountFlagBits depth_samples;
VkSampleCountFlagBits raster_samples;
bool positiveTest;
};
std::vector<TestCase> test_cases = {
{VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT,
false}, // Fails vk::CreateRenderPass and vk::CreateGraphicsPipeline
{VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT, false}, // Fails vk::CreateGraphicsPipeline
{VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_4_BIT, true} // Pass
};
for (const auto &test_case : test_cases) {
VkAttachmentDescription att[2] = {{}, {}};
att[0].format = VK_FORMAT_R8G8B8A8_UNORM;
att[0].samples = test_case.color_samples;
att[0].initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
att[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
att[1].format = ds_format;
att[1].samples = test_case.depth_samples;
att[1].initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
att[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference cr = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
VkAttachmentReference dr = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
VkSubpassDescription sp = {};
sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
sp.colorAttachmentCount = 1;
sp.pColorAttachments = &cr;
sp.pResolveAttachments = NULL;
sp.pDepthStencilAttachment = &dr;
VkRenderPassCreateInfo rpi = vku::InitStructHelper();
rpi.attachmentCount = 2;
rpi.pAttachments = att;
rpi.subpassCount = 1;
rpi.pSubpasses = &sp;
if (test_case.color_samples == test_case.depth_samples) {
} else {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSubpassDescription-pDepthStencilAttachment-01418");
}
vkt::RenderPass rp(*m_device, rpi);
if (test_case.color_samples == test_case.depth_samples) {
} else {
m_errorMonitor->VerifyFound();
continue;
}
VkPipelineDepthStencilStateCreateInfo ds = vku::InitStructHelper();
const auto break_samples = [&rp, &ds, &test_case](CreatePipelineHelper &helper) {
helper.pipe_ms_state_ci_.rasterizationSamples = test_case.raster_samples;
helper.gp_ci_.renderPass = rp.handle();
helper.gp_ci_.pDepthStencilState = &ds;
};
if (!test_case.positiveTest) {
CreatePipelineHelper::OneshotTest(*this, break_samples, kErrorBit,
"VUID-VkGraphicsPipelineCreateInfo-multisampledRenderToSingleSampled-06853");
} else {
CreatePipelineHelper::OneshotTest(*this, break_samples, kErrorBit);
}
}
}
TEST_F(NegativePipeline, FramebufferMixedSamplesCoverageReduction) {
TEST_DESCRIPTION("Verify VK_NV_coverage_reduction_mode.");
AddRequiredExtensions(VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME);
AddOptionalExtensions(VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME);
AddOptionalExtensions(VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
if (!IsExtensionsEnabled(VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME) &&
!IsExtensionsEnabled(VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME)) {
GTEST_SKIP() << "Extensions not supported";
}
RETURN_IF_SKIP(InitState())
InitRenderTarget();
struct TestCase {
VkSampleCountFlagBits raster_samples;
VkSampleCountFlagBits color_samples;
VkSampleCountFlagBits depth_samples;
VkCoverageReductionModeNV coverage_reduction_mode;
bool positiveTest;
std::string vuid;
};
std::vector<TestCase> test_cases;
uint32_t combination_count = 0;
std::vector<VkFramebufferMixedSamplesCombinationNV> combinations;
vk::GetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(gpu(), &combination_count, nullptr);
if (combination_count < 1) {
GTEST_SKIP() << "No mixed sample combinations are supported";
}
combinations.resize(combination_count);
// TODO this fill can be removed once https://github.com/KhronosGroup/Vulkan-ValidationLayers/pull/4138 merges
std::fill(combinations.begin(), combinations.end(), vku::InitStruct<VkFramebufferMixedSamplesCombinationNV>());
vk::GetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(gpu(), &combination_count, &combinations[0]);
// Pick the first supported combination for a positive test.
test_cases.push_back({combinations[0].rasterizationSamples, static_cast<VkSampleCountFlagBits>(combinations[0].colorSamples),
static_cast<VkSampleCountFlagBits>(combinations[0].depthStencilSamples),
combinations[0].coverageReductionMode, true,
"VUID-VkGraphicsPipelineCreateInfo-coverageReductionMode-02722"});
VkSampleCountFlags fb_sample_counts = m_device->phy().limits_.framebufferDepthSampleCounts;
int max_sample_count = VK_SAMPLE_COUNT_64_BIT;
while (max_sample_count > VK_SAMPLE_COUNT_1_BIT) {
if (fb_sample_counts & max_sample_count) {
break;
}
max_sample_count /= 2;
}
// Look for a valid combination that is not in the supported list for a negative test.
bool neg_comb_found = false;
for (int mode = VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV; mode >= 0 && !neg_comb_found; mode--) {
for (int rs = max_sample_count; rs >= VK_SAMPLE_COUNT_1_BIT && !neg_comb_found; rs /= 2) {
for (int ds = rs; ds >= 0 && !neg_comb_found; ds -= rs) {
for (int cs = rs / 2; cs > 0 && !neg_comb_found; cs /= 2) {
bool combination_found = false;
for (const auto &combination : combinations) {
if (mode == combination.coverageReductionMode && rs == combination.rasterizationSamples &&
ds & combination.depthStencilSamples && cs & combination.colorSamples) {
combination_found = true;
break;
}
}
if (!combination_found) {
neg_comb_found = true;
test_cases.push_back({static_cast<VkSampleCountFlagBits>(rs), static_cast<VkSampleCountFlagBits>(cs),
static_cast<VkSampleCountFlagBits>(ds), static_cast<VkCoverageReductionModeNV>(mode),
false, "VUID-VkGraphicsPipelineCreateInfo-coverageReductionMode-02722"});
}
}
}
}
}
for (const auto &test_case : test_cases) {
VkAttachmentDescription att[2] = {{}, {}};
att[0].format = VK_FORMAT_R8G8B8A8_UNORM;
att[0].samples = test_case.color_samples;
att[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
att[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
att[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
att[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
att[1].format = VK_FORMAT_D24_UNORM_S8_UINT;
att[1].samples = test_case.depth_samples;
att[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
att[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
att[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
att[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference cr = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
VkAttachmentReference dr = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
VkSubpassDescription sp = {};
sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
sp.colorAttachmentCount = 1;
sp.pColorAttachments = &cr;
sp.pResolveAttachments = nullptr;
sp.pDepthStencilAttachment = (test_case.depth_samples) ? &dr : nullptr;
VkRenderPassCreateInfo rpi = vku::InitStructHelper();
rpi.attachmentCount = (test_case.depth_samples) ? 2 : 1;
rpi.pAttachments = att;
rpi.subpassCount = 1;
rpi.pSubpasses = &sp;
vkt::RenderPass rp(*m_device, rpi);
ASSERT_TRUE(rp.initialized());
VkPipelineDepthStencilStateCreateInfo dss = vku::InitStructHelper();
VkPipelineCoverageReductionStateCreateInfoNV crs = vku::InitStructHelper();
const auto break_samples = [&rp, &dss, &crs, &test_case](CreatePipelineHelper &helper) {
crs.flags = 0;
crs.coverageReductionMode = test_case.coverage_reduction_mode;
helper.pipe_ms_state_ci_.pNext = &crs;
helper.pipe_ms_state_ci_.rasterizationSamples = test_case.raster_samples;
helper.gp_ci_.renderPass = rp.handle();
helper.gp_ci_.pDepthStencilState = (test_case.depth_samples) ? &dss : nullptr;
};
if (!test_case.positiveTest) {
CreatePipelineHelper::OneshotTest(*this, break_samples, kErrorBit, test_case.vuid);
} else {
CreatePipelineHelper::OneshotTest(*this, break_samples, kErrorBit);
}
}
}
TEST_F(NegativePipeline, FragmentCoverageToColorNV) {
TEST_DESCRIPTION("Verify VK_NV_fragment_coverage_to_color.");
AddRequiredExtensions(VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
struct TestCase {
VkFormat format;
VkBool32 enabled;
uint32_t location;
bool positive;
};
const std::array<TestCase, 9> test_cases = {{
{VK_FORMAT_R8G8B8A8_UNORM, VK_FALSE, 0, true},
{VK_FORMAT_R8_UINT, VK_TRUE, 1, true},
{VK_FORMAT_R16_UINT, VK_TRUE, 1, true},
{VK_FORMAT_R16_SINT, VK_TRUE, 1, true},
{VK_FORMAT_R32_UINT, VK_TRUE, 1, true},
{VK_FORMAT_R32_SINT, VK_TRUE, 1, true},
{VK_FORMAT_R32_SINT, VK_TRUE, 2, false},
{VK_FORMAT_R8_SINT, VK_TRUE, 3, false},
{VK_FORMAT_R8G8B8A8_UNORM, VK_TRUE, 1, false},
}};
for (const auto &test_case : test_cases) {
std::array<VkAttachmentDescription, 2> att = {{{}, {}}};
att[0].format = VK_FORMAT_R8G8B8A8_UNORM;
att[0].samples = VK_SAMPLE_COUNT_1_BIT;
att[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
att[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
att[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
att[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
att[1].format = VK_FORMAT_R8G8B8A8_UNORM;
att[1].samples = VK_SAMPLE_COUNT_1_BIT;
att[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
att[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
att[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
att[1].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
if (test_case.location < att.size()) {
att[test_case.location].format = test_case.format;
}
const std::array<VkAttachmentReference, 3> cr = {{{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
{1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
{VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}};
VkSubpassDescription sp = {};
sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
sp.colorAttachmentCount = cr.size();
sp.pColorAttachments = cr.data();
VkRenderPassCreateInfo rpi = vku::InitStructHelper();
rpi.attachmentCount = att.size();
rpi.pAttachments = att.data();
rpi.subpassCount = 1;
rpi.pSubpasses = &sp;
const std::array<VkPipelineColorBlendAttachmentState, 3> cba = {{{}, {}, {}}};
VkPipelineColorBlendStateCreateInfo cbi = vku::InitStructHelper();
cbi.attachmentCount = cba.size();
cbi.pAttachments = cba.data();
vkt::RenderPass rp(*m_device, rpi);
ASSERT_TRUE(rp.initialized());
VkPipelineCoverageToColorStateCreateInfoNV cci = vku::InitStructHelper();
const auto break_samples = [&cci, &cbi, &rp, &test_case](CreatePipelineHelper &helper) {
cci.coverageToColorEnable = test_case.enabled;
cci.coverageToColorLocation = test_case.location;
helper.pipe_ms_state_ci_.pNext = &cci;
helper.gp_ci_.renderPass = rp.handle();
helper.gp_ci_.pColorBlendState = &cbi;
};
if (!test_case.positive) {
CreatePipelineHelper::OneshotTest(*this, break_samples, kErrorBit,
"VUID-VkPipelineCoverageToColorStateCreateInfoNV-coverageToColorEnable-01404");
} else {
CreatePipelineHelper::OneshotTest(*this, break_samples, kErrorBit);
}
}
}
TEST_F(NegativePipeline, ViewportSwizzleNV) {
AddRequiredExtensions(VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
VkPipelineViewportSwizzleStateCreateInfoNV vp_swizzle_state = vku::InitStructHelper();
// Test invalid VkViewportSwizzleNV
{
const VkViewportSwizzleNV invalid_swizzles = {
static_cast<VkViewportCoordinateSwizzleNV>(-1),
static_cast<VkViewportCoordinateSwizzleNV>(-1),
static_cast<VkViewportCoordinateSwizzleNV>(-1),
static_cast<VkViewportCoordinateSwizzleNV>(-1),
};
vp_swizzle_state.viewportCount = 1;
vp_swizzle_state.pViewportSwizzles = &invalid_swizzles;
const std::vector<std::string> expected_vuids = {
"VUID-VkViewportSwizzleNV-x-parameter", "VUID-VkViewportSwizzleNV-y-parameter", "VUID-VkViewportSwizzleNV-z-parameter",
"VUID-VkViewportSwizzleNV-w-parameter"};
auto break_swizzles = [&vp_swizzle_state](CreatePipelineHelper &helper) { helper.vp_state_ci_.pNext = &vp_swizzle_state; };
CreatePipelineHelper::OneshotTest(*this, break_swizzles, kErrorBit, expected_vuids);
}
// Test case where VkPipelineViewportSwizzleStateCreateInfoNV::viewportCount is LESS THAN viewportCount set in
// VkPipelineViewportStateCreateInfo
{
const VkViewportSwizzleNV swizzle = {
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV, VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV,
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV, VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV};
vp_swizzle_state.viewportCount = 1;
vp_swizzle_state.pViewportSwizzles = &swizzle;
std::array<VkViewport, 2> viewports = {};
std::array<VkRect2D, 2> scissors = {};
viewports.fill({0, 0, 16, 16, 0, 1});
scissors.fill({{0, 0}, {16, 16}});
auto break_vp_count = [&vp_swizzle_state, &viewports, &scissors](CreatePipelineHelper &helper) {
helper.vp_state_ci_.viewportCount = size32(viewports);
helper.vp_state_ci_.pViewports = viewports.data();
helper.vp_state_ci_.scissorCount = size32(scissors);
helper.vp_state_ci_.pScissors = scissors.data();
helper.vp_state_ci_.pNext = &vp_swizzle_state;
ASSERT_TRUE(vp_swizzle_state.viewportCount < helper.vp_state_ci_.viewportCount);
};
CreatePipelineHelper::OneshotTest(*this, break_vp_count, kErrorBit,
"VUID-VkPipelineViewportSwizzleStateCreateInfoNV-viewportCount-01215");
}
}
TEST_F(NegativePipeline, CreationFeedbackCount) {
TEST_DESCRIPTION("Test graphics pipeline feedback stage count check.");
AddRequiredExtensions(VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
if (IsPlatformMockICD()) {
GTEST_SKIP() << "Driver data writeback check not supported by MockICD";
}
VkPipelineCreationFeedbackCreateInfoEXT feedback_info = vku::InitStructHelper();
VkPipelineCreationFeedbackEXT feedbacks[3] = {};
// Set flags to known value that the driver has to overwrite
feedbacks[0].flags = VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM;
feedback_info.pPipelineCreationFeedback = &feedbacks[0];
feedback_info.pipelineStageCreationFeedbackCount = 2;
feedback_info.pPipelineStageCreationFeedbacks = &feedbacks[1];
auto set_feedback = [&feedback_info](CreatePipelineHelper &helper) { helper.gp_ci_.pNext = &feedback_info; };
CreatePipelineHelper::OneshotTest(*this, set_feedback, kErrorBit);
if (feedback_info.pPipelineCreationFeedback->flags == VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM) {
m_errorMonitor->SetError("ValidationLayers did not return GraphicsPipelineFeedback driver data properly.");
}
feedback_info.pipelineStageCreationFeedbackCount = 1;
CreatePipelineHelper::OneshotTest(*this, set_feedback, kErrorBit,
"VUID-VkGraphicsPipelineCreateInfo-pipelineStageCreationFeedbackCount-06594");
}
TEST_F(NegativePipeline, CreationFeedbackCountCompute) {
TEST_DESCRIPTION("Test compute pipeline feedback stage count check.");
AddRequiredExtensions(VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
VkPipelineCreationFeedbackCreateInfoEXT feedback_info = vku::InitStructHelper();
VkPipelineCreationFeedbackEXT feedbacks[3] = {};
feedback_info.pPipelineCreationFeedback = &feedbacks[0];
feedback_info.pipelineStageCreationFeedbackCount = 1;
feedback_info.pPipelineStageCreationFeedbacks = &feedbacks[1];
const auto set_info = [&](CreateComputePipelineHelper &helper) { helper.cp_ci_.pNext = &feedback_info; };
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit);
feedback_info.pipelineStageCreationFeedbackCount = 2;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit,
"VUID-VkComputePipelineCreateInfo-pipelineStageCreationFeedbackCount-06566");
}
TEST_F(NegativePipeline, LineRasterization) {
TEST_DESCRIPTION("Test VK_EXT_line_rasterization state against feature enables.");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_features = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(line_rasterization_features);
line_rasterization_features.rectangularLines = VK_FALSE;
line_rasterization_features.bresenhamLines = VK_FALSE;
line_rasterization_features.smoothLines = VK_FALSE;
line_rasterization_features.stippledRectangularLines = VK_FALSE;
line_rasterization_features.stippledBresenhamLines = VK_FALSE;
line_rasterization_features.stippledSmoothLines = VK_FALSE;
RETURN_IF_SKIP(InitState(nullptr, &features2, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
InitRenderTarget();
{
constexpr std::array vuids = {"VUID-VkGraphicsPipelineCreateInfo-lineRasterizationMode-02766",
"VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02769"};
CreatePipelineHelper::OneshotTest(
*this,
[&](CreatePipelineHelper &helper) {
helper.line_state_ci_.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
helper.pipe_ms_state_ci_.alphaToCoverageEnable = VK_TRUE;
},
kErrorBit, vuids);
}
{
constexpr std::array vuids = {"VUID-VkGraphicsPipelineCreateInfo-stippledLineEnable-02767",
"VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02769",
"VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02772"};
CreatePipelineHelper::OneshotTest(
*this,
[&](CreatePipelineHelper &helper) {
helper.line_state_ci_.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
helper.line_state_ci_.stippledLineEnable = VK_TRUE;
},
kErrorBit, vuids);
}
{
constexpr std::array vuids = {"VUID-VkGraphicsPipelineCreateInfo-stippledLineEnable-02767",
"VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02768",
"VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02771"};
CreatePipelineHelper::OneshotTest(
*this,
[&](CreatePipelineHelper &helper) {
helper.line_state_ci_.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
helper.line_state_ci_.stippledLineEnable = VK_TRUE;
},
kErrorBit, vuids);
}
{
constexpr std::array vuids = {"VUID-VkGraphicsPipelineCreateInfo-stippledLineEnable-02767",
"VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02770",
"VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02773"};
CreatePipelineHelper::OneshotTest(
*this,
[&](CreatePipelineHelper &helper) {
helper.line_state_ci_.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
helper.line_state_ci_.stippledLineEnable = VK_TRUE;
},
kErrorBit, vuids);
}
{
constexpr std::array vuids = {"VUID-VkGraphicsPipelineCreateInfo-stippledLineEnable-02767",
"VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02774"};
CreatePipelineHelper::OneshotTest(
*this,
[&](CreatePipelineHelper &helper) {
helper.line_state_ci_.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT;
helper.line_state_ci_.stippledLineEnable = VK_TRUE;
},
kErrorBit, vuids);
}
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdSetLineStippleEXT-lineStippleFactor-02776");
vk::CmdSetLineStippleEXT(m_commandBuffer->handle(), 0, 0);
m_errorMonitor->VerifyFound();
vk::CmdSetLineStippleEXT(m_commandBuffer->handle(), 1, 1);
}
TEST_F(NegativePipeline, NotCompatibleForSet) {
TEST_DESCRIPTION("Check that validation path catches pipeline layout inconsistencies for bind vs. dispatch");
RETURN_IF_SKIP(Init())
if (m_device->compute_queues().empty()) {
GTEST_SKIP() << "compute queue not supported";
}
uint32_t qfi = 0;
VkBufferCreateInfo bci = vku::InitStructHelper();
bci.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
bci.size = 4;
bci.queueFamilyIndexCount = 1;
bci.pQueueFamilyIndices = &qfi;
VkMemoryPropertyFlags mem_props = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
vkt::Buffer storage_buffer(*m_device, bci, mem_props);
bci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
bci.size = 20;
vkt::Buffer uniform_buffer(*m_device, bci, mem_props);
OneOffDescriptorSet::Bindings binding_defs = {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
};
const vkt::DescriptorSetLayout pipeline_dsl(*m_device, binding_defs);
const vkt::PipelineLayout pipeline_layout(*m_device, {&pipeline_dsl});
// We now will use a slightly different Layout definition for the descriptors we acutally bind with (but that would still be
// correct for the shader
binding_defs[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
OneOffDescriptorSet binding_descriptor_set(m_device, binding_defs);
const vkt::PipelineLayout binding_pipeline_layout(*m_device, {&binding_descriptor_set.layout_});
VkDescriptorBufferInfo storage_buffer_info = {storage_buffer.handle(), 0, sizeof(uint32_t)};
VkDescriptorBufferInfo uniform_buffer_info = {uniform_buffer.handle(), 0, 5 * sizeof(uint32_t)};
VkWriteDescriptorSet descriptor_writes[2] = {};
descriptor_writes[0] = vku::InitStructHelper();
descriptor_writes[0].dstSet = binding_descriptor_set.set_;
descriptor_writes[0].dstBinding = 0;
descriptor_writes[0].descriptorCount = 1;
descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptor_writes[0].pBufferInfo = &storage_buffer_info;
descriptor_writes[1] = vku::InitStructHelper();
descriptor_writes[1].dstSet = binding_descriptor_set.set_;
descriptor_writes[1].dstBinding = 1;
descriptor_writes[1].descriptorCount = 1; // Write 4 bytes to val
descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_writes[1].pBufferInfo = &uniform_buffer_info;
vk::UpdateDescriptorSets(m_device->device(), 2, descriptor_writes, 0, NULL);
char const *csSource = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { uint index; } u_index;
layout(set = 0, binding = 1) uniform UniformStruct { ivec4 dummy; int val; } ubo;
void main() {
u_index.index = ubo.val;
}
)glsl";
VkShaderObj shader_module(this, csSource, VK_SHADER_STAGE_COMPUTE_BIT);
VkPipelineShaderStageCreateInfo stage = vku::InitStructHelper();
stage.flags = 0;
stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
stage.module = shader_module.handle();
stage.pName = "main";
stage.pSpecializationInfo = nullptr;
// CreateComputePipelines
VkComputePipelineCreateInfo pipeline_info = vku::InitStructHelper();
pipeline_info.flags = 0;
pipeline_info.layout = pipeline_layout.handle();
pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
pipeline_info.basePipelineIndex = -1;
pipeline_info.stage = stage;
VkPipeline c_pipeline;
vk::CreateComputePipelines(device(), VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &c_pipeline);
m_commandBuffer->begin();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, c_pipeline);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, binding_pipeline_layout.handle(), 0, 1,
&binding_descriptor_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDispatch-None-08600");
vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
vk::DestroyPipeline(device(), c_pipeline, nullptr);
}
TEST_F(VkLayerTest, PipelineMaxPerStageResources) {
TEST_DESCRIPTION("Check case where pipeline is created that exceeds maxPerStageResources");
RETURN_IF_SKIP(InitFramework())
PFN_vkSetPhysicalDeviceLimitsEXT fpvkSetPhysicalDeviceLimitsEXT = nullptr;
PFN_vkGetOriginalPhysicalDeviceLimitsEXT fpvkGetOriginalPhysicalDeviceLimitsEXT = nullptr;
if (!LoadDeviceProfileLayer(fpvkSetPhysicalDeviceLimitsEXT, fpvkGetOriginalPhysicalDeviceLimitsEXT)) {
GTEST_SKIP() << "Failed to load device profile layer.";
}
// Spec requires a minimum of 128 so know this is setting it lower than that
const uint32_t maxPerStageResources = 4;
VkPhysicalDeviceProperties props;
fpvkGetOriginalPhysicalDeviceLimitsEXT(gpu(), &props.limits);
props.limits.maxPerStageResources = maxPerStageResources;
fpvkSetPhysicalDeviceLimitsEXT(gpu(), &props.limits);
RETURN_IF_SKIP(InitState())
// Adds the one color attachment
InitRenderTarget();
// A case where it shouldn't error because no single stage is over limit
std::vector<VkDescriptorSetLayoutBinding> layout_bindings_normal = {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, maxPerStageResources, VK_SHADER_STAGE_VERTEX_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}};
// vertex test
std::vector<VkDescriptorSetLayoutBinding> layout_bindings_vert = {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, maxPerStageResources, VK_SHADER_STAGE_VERTEX_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}};
// fragment only has it at the limit because color attachment should push it over
std::vector<VkDescriptorSetLayoutBinding> layout_bindings_frag = {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, maxPerStageResources, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}};
// compute test
std::vector<VkDescriptorSetLayoutBinding> layout_bindings_comp = {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, maxPerStageResources, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}};
// Have case where it pushes limit from two setLayouts instead of two setLayoutBindings
std::vector<VkDescriptorSetLayoutBinding> layout_binding_combined0 = {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, maxPerStageResources, VK_SHADER_STAGE_VERTEX_BIT, nullptr}};
std::vector<VkDescriptorSetLayoutBinding> layout_binding_combined1 = {
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}};
const vkt::DescriptorSetLayout ds_layout_normal(*m_device, layout_bindings_normal);
const vkt::DescriptorSetLayout ds_layout_vert(*m_device, layout_bindings_vert);
const vkt::DescriptorSetLayout ds_layout_frag(*m_device, layout_bindings_frag);
const vkt::DescriptorSetLayout ds_layout_comp(*m_device, layout_bindings_comp);
const vkt::DescriptorSetLayout ds_layout_combined0(*m_device, layout_binding_combined0);
const vkt::DescriptorSetLayout ds_layout_combined1(*m_device, layout_binding_combined1);
CreateComputePipelineHelper compute_pipe(*this);
compute_pipe.InitState();
compute_pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&ds_layout_comp});
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkComputePipelineCreateInfo-layout-01687");
compute_pipe.CreateComputePipeline();
m_errorMonitor->VerifyFound();
{
CreatePipelineHelper graphics_pipe(*this);
graphics_pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&ds_layout_normal});
graphics_pipe.CreateGraphicsPipeline();
}
{
CreatePipelineHelper graphics_pipe(*this);
graphics_pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&ds_layout_vert});
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-layout-01688");
graphics_pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
{
CreatePipelineHelper graphics_pipe(*this);
graphics_pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&ds_layout_frag});
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-layout-01688");
graphics_pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
{
CreatePipelineHelper graphics_pipe(*this);
graphics_pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&ds_layout_combined0, &ds_layout_combined1});
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-layout-01688");
graphics_pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativePipeline, PipelineExecutablePropertiesFeature) {
TEST_DESCRIPTION("Try making calls without pipelineExecutableInfo.");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR pipeline_exe_features =
vku::InitStructHelper();
pipeline_exe_features.pipelineExecutableInfo = VK_FALSE; // Starting with it off
VkPhysicalDeviceFeatures2 features2 = vku::InitStructHelper(&pipeline_exe_features);
RETURN_IF_SKIP(InitState(nullptr, &features2))
InitRenderTarget();
// MockICD will return 0 for the executable count
if (IsPlatformMockICD()) {
GTEST_SKIP() << "Test not supported by MockICD";
}
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.CreateGraphicsPipeline();
uint32_t count;
VkPipelineExecutableInfoKHR pipeline_exe_info = vku::InitStructHelper();
pipeline_exe_info.pipeline = pipe.pipeline_;
pipeline_exe_info.executableIndex = 0;
VkPipelineInfoKHR pipeline_info = vku::InitStructHelper();
pipeline_info.pipeline = pipe.pipeline_;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-vkGetPipelineExecutableInternalRepresentationsKHR-pipelineExecutableInfo-03276");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkGetPipelineExecutableInternalRepresentationsKHR-pipeline-03278");
vk::GetPipelineExecutableInternalRepresentationsKHR(m_device->device(), &pipeline_exe_info, &count, nullptr);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkGetPipelineExecutableStatisticsKHR-pipelineExecutableInfo-03272");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkGetPipelineExecutableStatisticsKHR-pipeline-03274");
vk::GetPipelineExecutableStatisticsKHR(m_device->device(), &pipeline_exe_info, &count, nullptr);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkGetPipelineExecutablePropertiesKHR-pipelineExecutableInfo-03270");
vk::GetPipelineExecutablePropertiesKHR(m_device->device(), &pipeline_info, &count, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, SampledInvalidImageViews) {
TEST_DESCRIPTION("Test if an VkImageView is sampled at draw/dispatch that the format has valid format features enabled");
RETURN_IF_SKIP(Init())
InitRenderTarget();
PFN_vkSetPhysicalDeviceFormatPropertiesEXT fpvkSetPhysicalDeviceFormatPropertiesEXT = nullptr;
PFN_vkGetOriginalPhysicalDeviceFormatPropertiesEXT fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT = nullptr;
if (!LoadDeviceProfileLayer(fpvkSetPhysicalDeviceFormatPropertiesEXT, fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT)) {
GTEST_SKIP() << "Failed to load device profile layer.";
}
const VkFormat sampled_format = VK_FORMAT_R8G8B8A8_UNORM;
// Remove format features want to test if missing
VkFormatProperties formatProps;
fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT(gpu(), sampled_format, &formatProps);
formatProps.optimalTilingFeatures = (formatProps.optimalTilingFeatures & ~VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
fpvkSetPhysicalDeviceFormatPropertiesEXT(gpu(), sampled_format, formatProps);
VkImageObj image(m_device);
image.Init(128, 128, 1, sampled_format, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
ASSERT_TRUE(image.initialized());
VkImageView imageView = image.targetView(sampled_format);
// maps to VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
char const *fs_source_combined = R"glsl(
#version 450
layout (set=0, binding=0) uniform sampler2D samplerColor;
layout(location=0) out vec4 color;
void main() {
color = texture(samplerColor, gl_FragCoord.xy);
color += texture(samplerColor, gl_FragCoord.wz);
}
)glsl";
VkShaderObj fs_combined(this, fs_source_combined, VK_SHADER_STAGE_FRAGMENT_BIT);
// maps to VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE and VK_DESCRIPTOR_TYPE_SAMPLER
char const *fs_source_seperate = R"glsl(
#version 450
layout (set=0, binding=0) uniform texture2D textureColor;
layout (set=0, binding=1) uniform sampler samplers;
layout(location=0) out vec4 color;
void main() {
color = texture(sampler2D(textureColor, samplers), gl_FragCoord.xy);
}
)glsl";
VkShaderObj fs_seperate(this, fs_source_seperate, VK_SHADER_STAGE_FRAGMENT_BIT);
// maps to an unused image sampler that should not trigger validation as it is never sampled
char const *fs_source_unused = R"glsl(
#version 450
layout (set=0, binding=0) uniform sampler2D samplerColor;
layout(location=0) out vec4 color;
void main() {
color = vec4(gl_FragCoord.xyz, 1.0);
}
)glsl";
VkShaderObj fs_unused(this, fs_source_unused, VK_SHADER_STAGE_FRAGMENT_BIT);
// maps to VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER but makes sure it walks function tree to find sampling
char const *fs_source_function = R"glsl(
#version 450
layout (set=0, binding=0) uniform sampler2D samplerColor;
layout(location=0) out vec4 color;
vec4 foo() { return texture(samplerColor, gl_FragCoord.xy); }
vec4 bar(float x) { return (x > 0.5) ? foo() : vec4(1.0,1.0,1.0,1.0); }
void main() {
color = bar(gl_FragCoord.x);
}
)glsl";
VkShaderObj fs_function(this, fs_source_function, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipeline_combined(*this);
pipeline_combined.InitState();
CreatePipelineHelper pipeline_seperate(*this);
pipeline_seperate.InitState();
CreatePipelineHelper pipeline_unused(*this);
pipeline_unused.InitState();
CreatePipelineHelper pipeline_function(*this);
pipeline_function.InitState();
// 4 different pipelines for 4 different shaders
// 3 are invalid and 1 (pipeline_unused) is valid
pipeline_combined.shader_stages_[1] = fs_combined.GetStageCreateInfo();
pipeline_seperate.shader_stages_[1] = fs_seperate.GetStageCreateInfo();
pipeline_unused.shader_stages_[1] = fs_unused.GetStageCreateInfo();
pipeline_function.shader_stages_[1] = fs_function.GetStageCreateInfo();
OneOffDescriptorSet::Bindings combined_bindings = {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}};
OneOffDescriptorSet::Bindings seperate_bindings = {
{0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}};
OneOffDescriptorSet combined_descriptor_set(m_device, combined_bindings);
OneOffDescriptorSet seperate_descriptor_set(m_device, seperate_bindings);
const vkt::PipelineLayout combined_pipeline_layout(*m_device, {&combined_descriptor_set.layout_});
const vkt::PipelineLayout seperate_pipeline_layout(*m_device, {&seperate_descriptor_set.layout_});
pipeline_combined.gp_ci_.layout = combined_pipeline_layout.handle();
pipeline_seperate.gp_ci_.layout = seperate_pipeline_layout.handle();
pipeline_unused.gp_ci_.layout = combined_pipeline_layout.handle();
pipeline_function.gp_ci_.layout = combined_pipeline_layout.handle();
pipeline_combined.CreateGraphicsPipeline();
pipeline_seperate.CreateGraphicsPipeline();
pipeline_unused.CreateGraphicsPipeline();
pipeline_function.CreateGraphicsPipeline();
VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo();
sampler_ci.minFilter = VK_FILTER_LINEAR; // turned off feature bit for test
sampler_ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
sampler_ci.compareEnable = VK_FALSE;
vkt::Sampler sampler_filter(*m_device, sampler_ci);
sampler_ci.minFilter = VK_FILTER_NEAREST;
sampler_ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; // turned off feature bit for test
vkt::Sampler sampler_mipmap(*m_device, sampler_ci);
VkDescriptorImageInfo combined_sampler_info = {sampler_filter.handle(), imageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkDescriptorImageInfo seperate_sampled_image_info = {VK_NULL_HANDLE, imageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkDescriptorImageInfo seperate_sampler_info = {sampler_filter.handle(), VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED};
// first item is combined, second/third item are seperate
VkWriteDescriptorSet descriptor_writes[3] = {};
descriptor_writes[0] = vku::InitStructHelper();
descriptor_writes[0].dstSet = combined_descriptor_set.set_;
descriptor_writes[0].dstBinding = 0;
descriptor_writes[0].descriptorCount = 1;
descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_writes[0].pImageInfo = &combined_sampler_info;
descriptor_writes[1] = vku::InitStructHelper();
descriptor_writes[1].dstSet = seperate_descriptor_set.set_;
descriptor_writes[1].dstBinding = 0;
descriptor_writes[1].descriptorCount = 1;
descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
descriptor_writes[1].pImageInfo = &seperate_sampled_image_info;
descriptor_writes[2] = vku::InitStructHelper();
descriptor_writes[2].dstSet = seperate_descriptor_set.set_;
descriptor_writes[2].dstBinding = 1;
descriptor_writes[2].descriptorCount = 1;
descriptor_writes[2].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
descriptor_writes[2].pImageInfo = &seperate_sampler_info;
vk::UpdateDescriptorSets(m_device->device(), 3, descriptor_writes, 0, nullptr);
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
// Unused is a valid version of the combined pipeline/descriptors
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_unused.Handle());
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, combined_pipeline_layout.handle(), 0, 1,
&combined_descriptor_set.set_, 0, nullptr);
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
// Test magFilter
{
// Same descriptor set as combined test
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_function.Handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-magFilter-04553");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
// Draw with invalid combined image sampler
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_combined.Handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-magFilter-04553");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
// Same error, but not with seperate descriptors
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_seperate.Handle());
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, seperate_pipeline_layout.handle(), 0,
1, &seperate_descriptor_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-magFilter-04553");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
}
// Same test but for mipmap, so need to update descriptors
{
combined_sampler_info.sampler = sampler_mipmap.handle();
seperate_sampler_info.sampler = sampler_mipmap.handle();
vk::UpdateDescriptorSets(m_device->device(), 3, descriptor_writes, 0, nullptr);
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, combined_pipeline_layout.handle(), 0,
1, &combined_descriptor_set.set_, 0, nullptr);
// Same descriptor set as combined test
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_function.Handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-mipmapMode-04770");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
// Draw with invalid combined image sampler
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_combined.Handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-mipmapMode-04770");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
// Same error, but not with seperate descriptors
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_seperate.Handle());
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, seperate_pipeline_layout.handle(), 0,
1, &seperate_descriptor_set.set_, 0, nullptr);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-mipmapMode-04770");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativePipeline, ShaderDrawParametersNotEnabled10) {
TEST_DESCRIPTION("Validation using DrawParameters for Vulkan 1.0 without the shaderDrawParameters feature enabled.");
SetTargetApiVersion(VK_API_VERSION_1_0);
RETURN_IF_SKIP(Init())
InitRenderTarget();
if (DeviceValidationVersion() > VK_API_VERSION_1_0) {
GTEST_SKIP() << "Test requires Vulkan exactly 1.0";
}
char const *vsSource = R"glsl(
#version 460
void main(){
gl_Position = vec4(float(gl_BaseVertex));
}
)glsl";
VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL_TRY);
if (VK_SUCCESS == vs.InitFromGLSLTry()) {
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), helper.fs_->GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit,
vector<string>{"VUID-VkShaderModuleCreateInfo-pCode-08742", // Extension not enabled
"VUID-VkShaderModuleCreateInfo-pCode-08740"}); // The capability not valid
}
}
TEST_F(NegativePipeline, ShaderDrawParametersNotEnabled11) {
TEST_DESCRIPTION("Validation using DrawParameters for Vulkan 1.1 without the shaderDrawParameters feature enabled.");
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(Init())
InitRenderTarget();
char const *vsSource = R"glsl(
#version 460
void main(){
gl_Position = vec4(float(gl_BaseVertex));
}
)glsl";
VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_1, SPV_SOURCE_GLSL_TRY);
// make sure using SPIR-V 1.3 as extension is core and not needed in Vulkan then
if (VK_SUCCESS == vs.InitFromGLSLTry()) {
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), helper.fs_->GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkShaderModuleCreateInfo-pCode-08740");
}
}
TEST_F(NegativePipeline, CreateFlags) {
TEST_DESCRIPTION("Create a graphics pipeline with invalid VkPipelineCreateFlags.");
RETURN_IF_SKIP(Init())
InitRenderTarget();
VkPipelineCreateFlags flags;
const auto set_info = [&](CreatePipelineHelper &helper) { helper.gp_ci_.flags = flags; };
flags = VK_PIPELINE_CREATE_DISPATCH_BASE;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-00764");
flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit,
"VUID-VkGraphicsPipelineCreateInfo-graphicsPipelineLibrary-06606");
flags = VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-03372");
flags = VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-03373");
flags = VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-03374");
flags = VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-03375");
flags = VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-03376");
flags = VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-03377");
flags = VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-03577");
flags = VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-flags-04947");
}
TEST_F(NegativePipeline, CreateFlagsCompute) {
TEST_DESCRIPTION("Create a compute pipeline with invalid VkPipelineCreateFlags.");
RETURN_IF_SKIP(Init())
VkPipelineCreateFlags flags;
const auto set_info = [&](CreateComputePipelineHelper &helper) { helper.cp_ci_.flags = flags; };
flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-shaderEnqueue-09177");
flags = VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-03365");
flags = VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-03366");
flags = VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-03367");
flags = VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-03368");
flags = VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-03369");
flags = VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-03370");
flags = VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-03576");
flags = VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-04945");
flags = VK_PIPELINE_CREATE_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-07367");
flags = VK_PIPELINE_CREATE_RAY_TRACING_DISPLACEMENT_MICROMAP_BIT_NV;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-07996");
flags = VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV;
CreateComputePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-09007");
}
TEST_F(NegativePipeline, MergePipelineCachesInvalidDst) {
TEST_DESCRIPTION("Test mergeing pipeline caches with dst cache in src list");
RETURN_IF_SKIP(Init())
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.CreateGraphicsPipeline();
CreatePipelineHelper other_pipe(*this);
other_pipe.InitState();
other_pipe.CreateGraphicsPipeline();
VkPipelineCache dstCache = pipe.pipeline_cache_;
VkPipelineCache srcCaches[2] = {other_pipe.pipeline_cache_, pipe.pipeline_cache_};
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkMergePipelineCaches-dstCache-00770");
vk::MergePipelineCaches(m_device->device(), dstCache, 2, srcCaches);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, CreateComputesPipelineWithBadBasePointer) {
TEST_DESCRIPTION("Create Compute Pipeline with bad base pointer");
RETURN_IF_SKIP(Init())
char const *csSource = R"glsl(
#version 450
layout(local_size_x=2, local_size_y=4) in;
void main(){
}
)glsl";
VkShaderObj cs(this, csSource, VK_SHADER_STAGE_COMPUTE_BIT);
std::vector<VkDescriptorSetLayoutBinding> bindings(0);
const vkt::DescriptorSetLayout pipeline_dsl(*m_device, bindings);
const vkt::PipelineLayout pipeline_layout(*m_device, {&pipeline_dsl});
VkComputePipelineCreateInfo compute_create_info = vku::InitStructHelper();
compute_create_info.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT;
compute_create_info.stage = cs.GetStageCreateInfo();
compute_create_info.layout = pipeline_layout.handle();
vkt::Pipeline test_pipeline(*m_device, compute_create_info);
{
compute_create_info.basePipelineHandle = VK_NULL_HANDLE;
compute_create_info.basePipelineIndex = 1;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-07985");
VkPipeline pipeline;
vk::CreateComputePipelines(device(), VK_NULL_HANDLE, 1, &compute_create_info, nullptr, &pipeline);
m_errorMonitor->VerifyFound();
}
if (test_pipeline.initialized()) {
compute_create_info.basePipelineHandle = test_pipeline.handle();
compute_create_info.basePipelineIndex = 1;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkComputePipelineCreateInfo-flags-07986");
vkt::Pipeline pipeline(*m_device, compute_create_info);
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativePipeline, DiscardRectangle) {
TEST_DESCRIPTION("Create a graphics pipeline invalid VkPipelineDiscardRectangleStateCreateInfoEXT");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
VkPhysicalDeviceDiscardRectanglePropertiesEXT discard_rectangle_properties = vku::InitStructHelper();
GetPhysicalDeviceProperties2(discard_rectangle_properties);
uint32_t count = discard_rectangle_properties.maxDiscardRectangles + 1;
std::vector<VkRect2D> discard_rectangles(count);
VkPipelineDiscardRectangleStateCreateInfoEXT discard_rectangle_state =
vku::InitStructHelper();
discard_rectangle_state.discardRectangleCount = count;
discard_rectangle_state.pDiscardRectangles = discard_rectangles.data();
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.pNext = &discard_rectangle_state;
pipe.InitState();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-VkPipelineDiscardRectangleStateCreateInfoEXT-discardRectangleCount-00582");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, ColorWriteCreateInfoEXT) {
TEST_DESCRIPTION("Test VkPipelineColorWriteCreateInfoEXT in color blend state pNext");
AddRequiredExtensions(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
VkPipelineColorWriteCreateInfoEXT color_write = vku::InitStructHelper();
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.cb_ci_.pNext = &color_write;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineColorWriteCreateInfoEXT-attachmentCount-07608");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
VkBool32 enabled = VK_FALSE;
color_write.attachmentCount = 1;
color_write.pColorWriteEnables = &enabled;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineColorWriteCreateInfoEXT-pAttachments-04801");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, ColorWriteCreateInfoEXTMaxAttachments) {
TEST_DESCRIPTION("Test VkPipelineColorWriteCreateInfoEXT in color blend state pNext with too many attachments");
AddRequiredExtensions(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
uint32_t max_color_attachments = m_device->phy().limits_.maxColorAttachments + 1;
std::vector<VkBool32> enables(max_color_attachments, VK_TRUE);
VkPipelineColorWriteCreateInfoEXT color_write = vku::InitStructHelper();
color_write.attachmentCount = max_color_attachments;
color_write.pColorWriteEnables = enables.data();
std::vector<VkPipelineColorBlendAttachmentState> color_blends(max_color_attachments);
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.cb_ci_.pNext = &color_write;
pipe.cb_ci_.attachmentCount = max_color_attachments;
pipe.cb_ci_.pAttachments = color_blends.data();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineColorWriteCreateInfoEXT-attachmentCount-06655");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-07609");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, ValidateVariableSampleLocations) {
TEST_DESCRIPTION("Validate using VkPhysicalDeviceSampleLocationsPropertiesEXT");
AddRequiredExtensions(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
VkPhysicalDeviceSampleLocationsPropertiesEXT sample_locations = vku::InitStructHelper();
GetPhysicalDeviceProperties2(sample_locations);
if (sample_locations.variableSampleLocations) {
GTEST_SKIP() << "VkPhysicalDeviceSampleLocationsPropertiesEXT::variableSampleLocations is supported, skipping.";
}
VkAttachmentReference attach = {};
attach.layout = VK_IMAGE_LAYOUT_GENERAL;
VkSubpassDescription subpass = {};
subpass.pColorAttachments = &attach;
subpass.colorAttachmentCount = 1;
VkAttachmentDescription attach_desc = {};
attach_desc.format = VK_FORMAT_R8G8B8A8_UNORM;
attach_desc.samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attach_desc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkSubpassDescription subpasses[2] = {subpass, subpass};
VkSubpassDependency subpass_dependency = {0,
1,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_DEPENDENCY_BY_REGION_BIT};
VkRenderPassCreateInfo rpci = vku::InitStructHelper();
rpci.subpassCount = 2;
rpci.pSubpasses = subpasses;
rpci.attachmentCount = 1;
rpci.pAttachments = &attach_desc;
rpci.dependencyCount = 1;
rpci.pDependencies = &subpass_dependency;
vkt::RenderPass render_pass(*m_device, rpci);
ASSERT_TRUE(render_pass.initialized());
VkImageObj image(m_device);
image.Init(32, 32, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
VkImageView image_view = image.targetView(VK_FORMAT_R8G8B8A8_UNORM);
VkFramebufferCreateInfo framebuffer_info = vku::InitStructHelper();
framebuffer_info.renderPass = render_pass.handle();
framebuffer_info.attachmentCount = 1;
framebuffer_info.pAttachments = &image_view;
framebuffer_info.width = 32;
framebuffer_info.height = 32;
framebuffer_info.layers = 1;
vkt::Framebuffer framebuffer(*m_device, framebuffer_info);
ASSERT_TRUE(framebuffer.initialized());
VkMultisamplePropertiesEXT multisample_prop = vku::InitStructHelper();
vk::GetPhysicalDeviceMultisamplePropertiesEXT(gpu(), VK_SAMPLE_COUNT_1_BIT, &multisample_prop);
const uint32_t valid_count =
multisample_prop.maxSampleLocationGridSize.width * multisample_prop.maxSampleLocationGridSize.height;
if (valid_count == 0) {
printf("multisample properties are not supported.\n");
return;
}
std::vector<VkSampleLocationEXT> sample_location(valid_count, {0.5, 0.5});
VkSampleLocationsInfoEXT sample_locations_info = vku::InitStructHelper();
sample_locations_info.sampleLocationsPerPixel = VK_SAMPLE_COUNT_1_BIT;
sample_locations_info.sampleLocationGridSize = multisample_prop.maxSampleLocationGridSize;
sample_locations_info.sampleLocationsCount = valid_count;
sample_locations_info.pSampleLocations = sample_location.data();
VkPipelineSampleLocationsStateCreateInfoEXT sample_locations_state =
vku::InitStructHelper();
sample_locations_state.sampleLocationsEnable = VK_TRUE;
sample_locations_state.sampleLocationsInfo = sample_locations_info;
VkPipelineMultisampleStateCreateInfo multi_sample_state = vku::InitStructHelper(&sample_locations_state);
multi_sample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
multi_sample_state.sampleShadingEnable = VK_FALSE;
multi_sample_state.minSampleShading = 1.0;
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.gp_ci_.pMultisampleState = &multi_sample_state;
pipe.gp_ci_.renderPass = render_pass.handle();
pipe.CreateGraphicsPipeline();
VkClearValue clear_value;
clear_value.color.float32[0] = 0.25f;
clear_value.color.float32[1] = 0.25f;
clear_value.color.float32[2] = 0.25f;
clear_value.color.float32[3] = 0.0f;
VkAttachmentSampleLocationsEXT attachment_sample_locations;
attachment_sample_locations.attachmentIndex = 0;
attachment_sample_locations.sampleLocationsInfo = sample_locations_info;
VkSubpassSampleLocationsEXT subpass_sample_locations;
subpass_sample_locations.subpassIndex = 0;
subpass_sample_locations.sampleLocationsInfo = sample_locations_info;
VkRenderPassSampleLocationsBeginInfoEXT render_pass_sample_locations = vku::InitStructHelper();
render_pass_sample_locations.attachmentInitialSampleLocationsCount = 1;
render_pass_sample_locations.pAttachmentInitialSampleLocations = &attachment_sample_locations;
render_pass_sample_locations.postSubpassSampleLocationsCount = 1;
render_pass_sample_locations.pPostSubpassSampleLocations = &subpass_sample_locations;
sample_location[0].x =
0.0f; // Invalid, VkRenderPassSampleLocationsBeginInfoEXT wont match VkPipelineSampleLocationsStateCreateInfoEXT
VkRenderPassBeginInfo begin_info = vku::InitStructHelper(&render_pass_sample_locations);
begin_info.renderPass = render_pass.handle();
begin_info.framebuffer = framebuffer.handle();
begin_info.renderArea.extent.width = 32;
begin_info.renderArea.extent.height = 32;
begin_info.renderArea.offset.x = 0;
begin_info.renderArea.offset.y = 0;
begin_info.clearValueCount = 1;
begin_info.pClearValues = &clear_value;
m_commandBuffer->begin();
vk::CmdBeginRenderPass(m_commandBuffer->handle(), &begin_info, VK_SUBPASS_CONTENTS_INLINE);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindPipeline-variableSampleLocations-01525");
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_errorMonitor->VerifyFound();
m_commandBuffer->NextSubpass();
sample_location[0].x = 0.5f;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindPipeline-variableSampleLocations-01525");
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRenderPass();
begin_info.pNext = nullptr; // Invalid, missing VkRenderPassSampleLocationsBeginInfoEXT
vk::CmdBeginRenderPass(m_commandBuffer->handle(), &begin_info, VK_SUBPASS_CONTENTS_INLINE);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindPipeline-variableSampleLocations-01525");
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_errorMonitor->VerifyFound();
m_commandBuffer->NextSubpass();
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
TEST_F(NegativePipeline, RasterizationConservativeStateCreateInfo) {
TEST_DESCRIPTION("Test PipelineRasterizationConservativeStateCreateInfo.");
AddRequiredExtensions(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
VkPhysicalDeviceConservativeRasterizationPropertiesEXT conservative_rasterization_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(conservative_rasterization_props);
VkPipelineRasterizationConservativeStateCreateInfoEXT conservative_state =
vku::InitStructHelper();
conservative_state.extraPrimitiveOverestimationSize = -1.0f;
CreatePipelineHelper pipe(*this);
pipe.rs_state_ci_.pNext = &conservative_state;
pipe.InitState();
m_errorMonitor->SetDesiredFailureMsg(
kErrorBit, "VUID-VkPipelineRasterizationConservativeStateCreateInfoEXT-extraPrimitiveOverestimationSize-01769");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
conservative_state.extraPrimitiveOverestimationSize =
conservative_rasterization_props.maxExtraPrimitiveOverestimationSize + 0.1f;
m_errorMonitor->SetDesiredFailureMsg(
kErrorBit, "VUID-VkPipelineRasterizationConservativeStateCreateInfoEXT-extraPrimitiveOverestimationSize-01769");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, CreateGraphicsPipelineNullRenderPass) {
TEST_DESCRIPTION("Test for a creating a pipeline with a null renderpass but VK_KHR_dynamic_rendering is not enabled");
RETURN_IF_SKIP(Init())
char const *fsSource = R"glsl(
#version 450
layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput x;
layout(location=0) out vec4 color;
void main() {
color = subpassLoad(x);
}
)glsl";
VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
VkDescriptorSetLayoutBinding dslb = {0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
const vkt::DescriptorSetLayout dsl(*m_device, {dslb});
const vkt::PipelineLayout pl(*m_device, {&dsl});
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06575");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06603");
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.gp_ci_.layout = pl.handle();
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, RasterizationOrderAttachmentAccessWithoutFeature) {
TEST_DESCRIPTION("Test for a creating a pipeline with VK_ARM_rasterization_order_attachment_access enabled");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_features = vku::InitStructHelper();
GetPhysicalDeviceFeatures2(rasterization_order_features);
rasterization_order_features.rasterizationOrderColorAttachmentAccess = 0;
rasterization_order_features.rasterizationOrderDepthAttachmentAccess = 0;
rasterization_order_features.rasterizationOrderStencilAttachmentAccess = 0;
RETURN_IF_SKIP(InitState(nullptr, &rasterization_order_features));
VkPipelineDepthStencilStateCreateInfo ds_ci = vku::InitStructHelper();
VkPipelineColorBlendAttachmentState cb_as = {};
VkPipelineColorBlendStateCreateInfo cb_ci = vku::InitStructHelper();
cb_ci.attachmentCount = 1;
cb_ci.pAttachments = &cb_as;
VkAttachmentDescription attachments[2] = {};
attachments[0].flags = 0;
attachments[0].format = VK_FORMAT_B8G8R8A8_UNORM;
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[1].flags = 0;
attachments[1].format = FindSupportedDepthStencilFormat(this->gpu());
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference cAttachRef = {};
cAttachRef.attachment = 0;
cAttachRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference dsAttachRef = {};
dsAttachRef.attachment = 1;
dsAttachRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &cAttachRef;
subpass.pDepthStencilAttachment = &dsAttachRef;
subpass.flags = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM |
VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM |
VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM;
VkRenderPassCreateInfo rpci = vku::InitStructHelper();
rpci.attachmentCount = 2;
rpci.pAttachments = attachments;
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
vkt::RenderPass render_pass(*m_device, rpci);
auto set_info = [&](CreatePipelineHelper &helper) {
helper.gp_ci_.pDepthStencilState = &ds_ci;
helper.gp_ci_.pColorBlendState = &cb_ci;
helper.gp_ci_.renderPass = render_pass.handle();
};
// Color attachment
cb_ci.flags = VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM;
ds_ci.flags = 0;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit,
"VUID-VkPipelineColorBlendStateCreateInfo-rasterizationOrderColorAttachmentAccess-06465");
// Depth attachment
cb_ci.flags = 0;
ds_ci.flags = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit,
"VUID-VkPipelineDepthStencilStateCreateInfo-rasterizationOrderDepthAttachmentAccess-06463");
// Stencil attachment
cb_ci.flags = 0;
ds_ci.flags = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM;
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit,
"VUID-VkPipelineDepthStencilStateCreateInfo-rasterizationOrderStencilAttachmentAccess-06464");
}
TEST_F(NegativePipeline, RasterizationOrderAttachmentAccessNoSubpassFlags) {
TEST_DESCRIPTION("Test for a creating a pipeline with VK_ARM_rasterization_order_attachment_access enabled");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_features = vku::InitStructHelper();
GetPhysicalDeviceFeatures2(rasterization_order_features);
if (!rasterization_order_features.rasterizationOrderColorAttachmentAccess &&
!rasterization_order_features.rasterizationOrderDepthAttachmentAccess &&
!rasterization_order_features.rasterizationOrderStencilAttachmentAccess) {
GTEST_SKIP() << "Test requires (unsupported) rasterizationOrder*AttachmentAccess";
}
RETURN_IF_SKIP(InitState(nullptr, &rasterization_order_features));
VkPipelineDepthStencilStateCreateInfo ds_ci = vku::InitStructHelper();
VkPipelineColorBlendAttachmentState cb_as = {};
VkPipelineColorBlendStateCreateInfo cb_ci = vku::InitStructHelper();
cb_ci.attachmentCount = 1;
cb_ci.pAttachments = &cb_as;
VkRenderPass render_pass_handle = VK_NULL_HANDLE;
auto create_render_pass = [&](VkPipelineDepthStencilStateCreateFlags subpass_flags, vkt::RenderPass &render_pass) {
VkAttachmentDescription attachments[2] = {};
attachments[0].flags = 0;
attachments[0].format = VK_FORMAT_B8G8R8A8_UNORM;
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[1].flags = 0;
attachments[1].format = FindSupportedDepthStencilFormat(this->gpu());
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference cAttachRef = {};
cAttachRef.attachment = 0;
cAttachRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference dsAttachRef = {};
dsAttachRef.attachment = 1;
dsAttachRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &cAttachRef;
subpass.pDepthStencilAttachment = &dsAttachRef;
subpass.flags = subpass_flags;
VkRenderPassCreateInfo rpci = vku::InitStructHelper();
rpci.attachmentCount = 2;
rpci.pAttachments = attachments;
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
render_pass.init(*this->m_device, rpci);
};
auto set_flgas_pipeline_createinfo = [&](CreatePipelineHelper &helper) {
helper.gp_ci_.pDepthStencilState = &ds_ci;
helper.gp_ci_.pColorBlendState = &cb_ci;
helper.gp_ci_.renderPass = render_pass_handle;
};
vkt::RenderPass render_pass_no_flags;
create_render_pass(0, render_pass_no_flags);
render_pass_handle = render_pass_no_flags.handle();
// Color attachment
if (rasterization_order_features.rasterizationOrderColorAttachmentAccess) {
cb_ci.flags = VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM;
ds_ci.flags = 0;
// Expecting VUID-VkGraphicsPipelineCreateInfo-flags-06484 Error
CreatePipelineHelper::OneshotTest(*this, set_flgas_pipeline_createinfo, kErrorBit,
"VUID-VkGraphicsPipelineCreateInfo-flags-06484");
}
// Depth attachment
if (rasterization_order_features.rasterizationOrderDepthAttachmentAccess) {
cb_ci.flags = 0;
ds_ci.flags = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM;
// Expecting VUID-VkGraphicsPipelineCreateInfo-flags-06485 Error
CreatePipelineHelper::OneshotTest(*this, set_flgas_pipeline_createinfo, kErrorBit,
"VUID-VkGraphicsPipelineCreateInfo-flags-06485");
}
// Stencil attachment
if (rasterization_order_features.rasterizationOrderStencilAttachmentAccess) {
cb_ci.flags = 0;
ds_ci.flags = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM;
// Expecting VUID-VkGraphicsPipelineCreateInfo-flags-06486 Error
CreatePipelineHelper::OneshotTest(*this, set_flgas_pipeline_createinfo, kErrorBit,
"VUID-VkGraphicsPipelineCreateInfo-flags-06486");
}
if (rasterization_order_features.rasterizationOrderDepthAttachmentAccess) {
char const *fsSource = R"glsl(
#version 450
layout(early_fragment_tests) in;
layout(location = 0) out vec4 uFragColor;
void main() {
uFragColor = vec4(0,1,0,1);
}
)glsl";
VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
auto set_stages_pipeline_createinfo = [&](CreatePipelineHelper &helper) {
helper.gp_ci_.pDepthStencilState = &ds_ci;
helper.gp_ci_.pColorBlendState = &cb_ci;
helper.gp_ci_.renderPass = render_pass_handle;
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
cb_ci.flags = 0;
ds_ci.flags = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM;
vkt::RenderPass render_pass;
create_render_pass(VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM, render_pass);
render_pass_handle = render_pass.handle();
CreatePipelineHelper::OneshotTest(*this, set_stages_pipeline_createinfo, kErrorBit,
"VUID-VkGraphicsPipelineCreateInfo-flags-06591");
}
}
TEST_F(NegativePipeline, MismatchedRenderPassAndPipelineAttachments) {
TEST_DESCRIPTION("Test creating a pipeline with no attachments with a render pass with attachments.");
RETURN_IF_SKIP(Init())
InitRenderTarget();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-07609");
char const *vsSource = R"glsl(
#version 450
void main() {
}
)glsl";
char const *fsSource = R"glsl(
#version 450
void main() {
}
)glsl";
VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
VkDescriptorSetLayoutBinding layout_binding = {};
layout_binding.binding = 1;
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
layout_binding.descriptorCount = 1;
layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
layout_binding.pImmutableSamplers = nullptr;
const vkt::DescriptorSetLayout descriptor_set_layout(*m_device, {layout_binding});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set_layout});
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.layout = pipeline_layout.handle();
pipe.cb_ci_ = vku::InitStructHelper();
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, IncompatibleScissorCountAndViewportCount) {
TEST_DESCRIPTION("Validate creating a pipeline with incompatible scissor and viewport count, without dynamic states.");
SetTargetApiVersion(VK_API_VERSION_1_3);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
VkPhysicalDeviceFeatures features{};
vk::GetPhysicalDeviceFeatures(gpu(), &features);
if (features.multiViewport == false) {
GTEST_SKIP() << "multiViewport feature not supported by device";
}
VkViewport viewports[2] = {{0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}};
auto set_viewport_state_createinfo = [&](CreatePipelineHelper &helper) {
helper.vp_state_ci_.viewportCount = 2;
helper.vp_state_ci_.pViewports = viewports;
};
CreatePipelineHelper::OneshotTest(*this, set_viewport_state_createinfo, kErrorBit,
"VUID-VkPipelineViewportStateCreateInfo-scissorCount-04134");
}
TEST_F(NegativePipeline, ShaderTileImageDisabled) {
TEST_DESCRIPTION("Validate creating graphics pipeline without shader tile image features enabled.");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_EXT_SHADER_TILE_IMAGE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamic_rendering_features = vku::InitStructHelper();
VkPhysicalDeviceShaderTileImageFeaturesEXT shader_tile_image_features = vku::InitStructHelper();
dynamic_rendering_features.pNext = &shader_tile_image_features;
auto features2 = GetPhysicalDeviceFeatures2(dynamic_rendering_features);
if (!dynamic_rendering_features.dynamicRendering) {
GTEST_SKIP() << "Test requires (unsupported) dynamicRendering";
}
// None of the shader tile image read features supported skip the test.
if (!shader_tile_image_features.shaderTileImageColorReadAccess && !shader_tile_image_features.shaderTileImageDepthReadAccess &&
!shader_tile_image_features.shaderTileImageStencilReadAccess) {
GTEST_SKIP() << "Test requires (unsupported) shader tile image extension.";
}
shader_tile_image_features.shaderTileImageColorReadAccess = false;
shader_tile_image_features.shaderTileImageDepthReadAccess = false;
shader_tile_image_features.shaderTileImageStencilReadAccess = false;
RETURN_IF_SKIP(InitState(nullptr, &features2))
VkFormat depth_format = VK_FORMAT_D32_SFLOAT_S8_UINT;
VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM;
VkPipelineRenderingCreateInfoKHR pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_format;
pipeline_rendering_info.depthAttachmentFormat = depth_format;
pipeline_rendering_info.stencilAttachmentFormat = depth_format;
if (shader_tile_image_features.shaderTileImageDepthReadAccess) {
auto fs = VkShaderObj::CreateFromASM(this, kShaderTileImageDepthReadSpv, VK_SHADER_STAGE_FRAGMENT_BIT);
auto pipeline_createinfo = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs->GetStageCreateInfo()};
helper.gp_ci_.renderPass = VK_NULL_HANDLE;
helper.gp_ci_.pNext = &pipeline_rendering_info;
};
CreatePipelineHelper::OneshotTest(*this, pipeline_createinfo, kErrorBit,
"VUID-RuntimeSpirv-shaderTileImageDepthReadAccess-08729");
}
if (shader_tile_image_features.shaderTileImageStencilReadAccess) {
auto fs = VkShaderObj::CreateFromASM(this, kShaderTileImageStencilReadSpv, VK_SHADER_STAGE_FRAGMENT_BIT);
auto pipeline_createinfo = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs->GetStageCreateInfo()};
helper.gp_ci_.renderPass = VK_NULL_HANDLE;
helper.gp_ci_.pNext = &pipeline_rendering_info;
};
CreatePipelineHelper::OneshotTest(*this, pipeline_createinfo, kErrorBit,
"VUID-RuntimeSpirv-shaderTileImageStencilReadAccess-08730");
}
if (shader_tile_image_features.shaderTileImageColorReadAccess) {
auto fs = VkShaderObj::CreateFromASM(this, kShaderTileImageColorReadSpv, VK_SHADER_STAGE_FRAGMENT_BIT);
auto pipeline_createinfo_with_ms = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs->GetStageCreateInfo()};
helper.gp_ci_.renderPass = VK_NULL_HANDLE;
helper.gp_ci_.pNext = &pipeline_rendering_info;
};
CreatePipelineHelper::OneshotTest(*this, pipeline_createinfo_with_ms, kErrorBit,
"VUID-RuntimeSpirv-shaderTileImageColorReadAccess-08728");
}
}
TEST_F(NegativePipeline, ShaderTileImage) {
TEST_DESCRIPTION("Validate creating graphics pipeline with shader tile image extension.");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_EXT_SHADER_TILE_IMAGE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamic_rendering_features = vku::InitStructHelper();
VkPhysicalDeviceShaderTileImageFeaturesEXT shader_tile_image_features = vku::InitStructHelper();
dynamic_rendering_features.pNext = &shader_tile_image_features;
auto features2 = GetPhysicalDeviceFeatures2(dynamic_rendering_features);
if (!dynamic_rendering_features.dynamicRendering) {
GTEST_SKIP() << "Test requires (unsupported) dynamicRendering";
}
// None of the shader tile image read features supported skip the test.
if (!shader_tile_image_features.shaderTileImageColorReadAccess && !shader_tile_image_features.shaderTileImageDepthReadAccess &&
!shader_tile_image_features.shaderTileImageStencilReadAccess) {
GTEST_SKIP() << "Test requires (unsupported) shader tile image extension.";
}
RETURN_IF_SKIP(InitState(nullptr, &features2))
VkFormat depth_format = VK_FORMAT_D32_SFLOAT_S8_UINT;
VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM;
VkPipelineRenderingCreateInfoKHR pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_format;
pipeline_rendering_info.depthAttachmentFormat = depth_format;
pipeline_rendering_info.stencilAttachmentFormat = depth_format;
VkPipelineDepthStencilStateCreateInfo ds_ci = vku::InitStructHelper();
if (shader_tile_image_features.shaderTileImageDepthReadAccess) {
auto fs = VkShaderObj::CreateFromASM(this, kShaderTileImageDepthReadSpv, VK_SHADER_STAGE_FRAGMENT_BIT);
auto pipeline_createinfo = [&](CreatePipelineHelper &helper) {
ds_ci.depthWriteEnable = true;
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs->GetStageCreateInfo()};
helper.gp_ci_.pDepthStencilState = &ds_ci;
helper.gp_ci_.renderPass = VK_NULL_HANDLE;
helper.gp_ci_.pNext = &pipeline_rendering_info;
};
CreatePipelineHelper::OneshotTest(*this, pipeline_createinfo, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-pStages-08711");
}
if (shader_tile_image_features.shaderTileImageStencilReadAccess) {
auto fs = VkShaderObj::CreateFromASM(this, kShaderTileImageStencilReadSpv, VK_SHADER_STAGE_FRAGMENT_BIT);
VkStencilOpState stencil_state = {};
stencil_state.failOp = VK_STENCIL_OP_KEEP;
stencil_state.depthFailOp = VK_STENCIL_OP_KEEP;
stencil_state.passOp = VK_STENCIL_OP_REPLACE;
stencil_state.compareOp = VK_COMPARE_OP_LESS;
stencil_state.compareMask = 0xff;
stencil_state.writeMask = 0xff;
stencil_state.reference = 0xf;
ds_ci = {};
ds_ci.front = stencil_state;
ds_ci.back = stencil_state;
auto pipeline_createinfo = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs->GetStageCreateInfo()};
helper.gp_ci_.pDepthStencilState = &ds_ci;
helper.gp_ci_.renderPass = VK_NULL_HANDLE;
helper.gp_ci_.pNext = &pipeline_rendering_info;
};
CreatePipelineHelper::OneshotTest(*this, pipeline_createinfo, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-pStages-08712");
}
if (shader_tile_image_features.shaderTileImageColorReadAccess) {
auto fs = VkShaderObj::CreateFromASM(this, kShaderTileImageColorReadSpv, VK_SHADER_STAGE_FRAGMENT_BIT);
VkAttachmentReference attachmentRefs[1] = {};
attachmentRefs[0].layout = VK_IMAGE_LAYOUT_GENERAL;
attachmentRefs[0].attachment = 0;
VkSubpassDescription subpass = {};
subpass.flags = 0;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &attachmentRefs[0];
VkRenderPassCreateInfo rp_ci = vku::InitStructHelper();
rp_ci.subpassCount = 1;
rp_ci.pSubpasses = &subpass;
rp_ci.attachmentCount = 1;
VkAttachmentDescription attach_desc[1] = {};
attach_desc[0].format = VK_FORMAT_B8G8R8A8_UNORM;
attach_desc[0].samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attach_desc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attach_desc[0].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
rp_ci.pAttachments = attach_desc;
vkt::RenderPass render_pass(*m_device, rp_ci);
// Check if the colorAttachmentRead capability enable, renderpass should be null
auto pipeline_createinfo = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs->GetStageCreateInfo()};
helper.gp_ci_.renderPass = render_pass.handle();
};
CreatePipelineHelper::OneshotTest(*this, pipeline_createinfo, kErrorBit,
"VUID-VkGraphicsPipelineCreateInfo-renderPass-08710");
// sampleShading enable and minSampleShading not equal to 1.0
VkPipelineMultisampleStateCreateInfo ms_ci = vku::InitStructHelper();
ms_ci.sampleShadingEnable = VK_TRUE;
ms_ci.minSampleShading = 0;
ms_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
pipeline_rendering_info.depthAttachmentFormat = VK_FORMAT_UNDEFINED;
pipeline_rendering_info.stencilAttachmentFormat = VK_FORMAT_UNDEFINED;
auto pipeline_createinfo_with_ms = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs->GetStageCreateInfo()};
helper.gp_ci_.pMultisampleState = &ms_ci;
helper.gp_ci_.renderPass = VK_NULL_HANDLE;
helper.gp_ci_.pNext = &pipeline_rendering_info;
};
CreatePipelineHelper::OneshotTest(*this, pipeline_createinfo_with_ms, kErrorBit,
"VUID-RuntimeSpirv-minSampleShading-08732");
}
}
TEST_F(NegativePipeline, PipelineSubpassOutOfBounds) {
TEST_DESCRIPTION("Create pipeline with subpass index larger than number of subpasses in render pass");
RETURN_IF_SKIP(Init())
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.gp_ci_.subpass = 4u;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06046");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, PipelineRenderingInfoInvalidFormats) {
TEST_DESCRIPTION("Create pipeline with invalid pipeline rendering formats");
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering_features = vku::InitStructHelper();
GetPhysicalDeviceFeatures2(dynamic_rendering_features);
RETURN_IF_SKIP(InitState(nullptr, &dynamic_rendering_features));
VkPipelineRenderingCreateInfo pipeline_rendering_ci = vku::InitStructHelper();
pipeline_rendering_ci.depthAttachmentFormat = VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT;
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.gp_ci_.renderPass = VK_NULL_HANDLE;
pipe.gp_ci_.pNext = &pipeline_rendering_ci;
pipe.cb_ci_.attachmentCount = 0u;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06583");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06587");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
pipeline_rendering_ci.depthAttachmentFormat = VK_FORMAT_UNDEFINED;
pipeline_rendering_ci.stencilAttachmentFormat = VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06584");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06588");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, RasterStateWithDepthBiasRepresentationInfo) {
TEST_DESCRIPTION(
"VkDepthBiasRepresentationInfoEXT in VkPipelineRasterizationStateCreateInfo pNext chain, but with "
"VkPhysicalDeviceDepthBiasControlFeaturesEXT features disabled");
AddRequiredExtensions(VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceDepthBiasControlFeaturesEXT depth_bias_control_features = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(depth_bias_control_features);
if (!depth_bias_control_features.depthBiasControl) {
GTEST_SKIP() << "depthBiasControl not supported";
}
features2.features.depthBiasClamp =
VK_FALSE; // Make sure validation of VkDepthBiasRepresentationInfoEXT in VkPipelineRasterizationStateCreateInfo does not
// rely on depthBiasClamp being enabled
depth_bias_control_features.leastRepresentableValueForceUnormRepresentation = VK_FALSE;
depth_bias_control_features.floatRepresentation = VK_FALSE;
depth_bias_control_features.depthBiasExact = VK_FALSE;
RETURN_IF_SKIP(InitState(nullptr, &features2))
InitRenderTarget();
const auto create_pipe_with_depth_bias_representation = [this](VkDepthBiasRepresentationInfoEXT &depth_bias_representation) {
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS);
const VkPipelineRasterizationStateCreateInfo raster_state = vku::InitStructHelper(&depth_bias_representation);
pipe.rs_state_ci_ = raster_state;
pipe.CreateGraphicsPipeline();
};
VkDepthBiasRepresentationInfoEXT depth_bias_representation = vku::InitStructHelper();
depth_bias_representation.depthBiasRepresentation = VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT;
depth_bias_representation.depthBiasExact = VK_TRUE;
m_errorMonitor->SetDesiredFailureMsg(
kErrorBit, "VUID-VkDepthBiasRepresentationInfoEXT-leastRepresentableValueForceUnormRepresentation-08947");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDepthBiasRepresentationInfoEXT-depthBiasExact-08949");
create_pipe_with_depth_bias_representation(depth_bias_representation);
m_errorMonitor->VerifyFound();
depth_bias_representation.depthBiasExact = VK_FALSE;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDepthBiasRepresentationInfoEXT-floatRepresentation-08948");
depth_bias_representation.depthBiasRepresentation = VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT;
create_pipe_with_depth_bias_representation(depth_bias_representation);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, InvalidPipelineDepthBias) {
TEST_DESCRIPTION("Create pipeline with invalid depth bias");
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceFeatures features = {};
RETURN_IF_SKIP(InitState(&features));
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.rs_state_ci_.depthBiasEnable = VK_TRUE;
pipe.rs_state_ci_.depthBiasClamp = 0.5f;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00754");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, MismatchedRasterizationSamples) {
TEST_DESCRIPTION("Draw when render pass rasterization samples do not match pipeline rasterization samples");
AddRequiredExtensions(VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT msrtss_features = vku::InitStructHelper();
VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamic_rendering_features = vku::InitStructHelper(&msrtss_features);
GetPhysicalDeviceFeatures2(dynamic_rendering_features);
if (!msrtss_features.multisampledRenderToSingleSampled) {
GTEST_SKIP() << "Test requires (unsupported) multisampledRenderToSingleSampled";
}
if (!dynamic_rendering_features.dynamicRendering) {
GTEST_SKIP() << "Test requires (unsupported) dynamicRendering";
}
RETURN_IF_SKIP(InitState(nullptr, &dynamic_rendering_features));
VkImageObj image(m_device);
VkImageCreateInfo image_ci = vku::InitStructHelper();
image_ci.flags = VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT;
image_ci.imageType = VK_IMAGE_TYPE_2D;
image_ci.format = VK_FORMAT_R8G8B8A8_UNORM;
image_ci.extent = {128u, 128u, 1u};
image_ci.mipLevels = 1u;
image_ci.arrayLayers = 1u;
image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
image_ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
image_ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImageFormatProperties formProps;
VkResult res = vk::GetPhysicalDeviceImageFormatProperties(m_device->phy().handle(), image_ci.format, image_ci.imageType,
image_ci.tiling, image_ci.usage, image_ci.flags, &formProps);
if (res != VK_SUCCESS || (formProps.sampleCounts & VK_SAMPLE_COUNT_2_BIT) == 0) {
GTEST_SKIP() << "Required format not supported";
}
image.init(&image_ci);
VkImageView image_view = image.targetView(image_ci.format);
VkRenderingAttachmentInfoKHR color_attachment = vku::InitStructHelper();
color_attachment.imageView = image_view;
color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkMultisampledRenderToSingleSampledInfoEXT rtss = vku::InitStructHelper();
rtss.multisampledRenderToSingleSampledEnable = VK_TRUE;
rtss.rasterizationSamples = VK_SAMPLE_COUNT_2_BIT;
VkRenderingInfo rendering_info = vku::InitStructHelper(&rtss);
rendering_info.renderArea = {{0, 0}, {1, 1}};
rendering_info.layerCount = 1u;
rendering_info.colorAttachmentCount = 1u;
rendering_info.pColorAttachments = &color_attachment;
VkPipelineRenderingCreateInfoKHR pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &image_ci.format;
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.gp_ci_.pNext = &pipeline_rendering_info;
pipe.gp_ci_.renderPass = VK_NULL_HANDLE;
pipe.CreateGraphicsPipeline();
m_commandBuffer->begin();
m_commandBuffer->BeginRendering(rendering_info);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-pNext-07935");
vk::CmdDraw(m_commandBuffer->handle(), 4u, 1u, 0u, 0u);
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRendering();
m_commandBuffer->end();
}
TEST_F(NegativePipeline, PipelineMissingFeatures) {
TEST_DESCRIPTION("Enabled depth bounds when the features is disabled");
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceFeatures features = {};
RETURN_IF_SKIP(InitState(&features));
VkAttachmentDescription attachment = {};
attachment.format = FindSupportedDepthStencilFormat(m_device->phy().handle());
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference dr = {0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
VkSubpassDescription sp = {};
sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
sp.pDepthStencilAttachment = &dr;
VkRenderPassCreateInfo rpi = vku::InitStructHelper();
rpi.attachmentCount = 1;
rpi.pAttachments = &attachment;
rpi.subpassCount = 1;
rpi.pSubpasses = &sp;
vkt::RenderPass rp(*m_device, rpi);
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.ds_ci_ = vku::InitStructHelper();
pipe.ds_ci_.depthBoundsTestEnable = VK_TRUE;
pipe.gp_ci_.renderPass = rp.handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineDepthStencilStateCreateInfo-depthBoundsTestEnable-00598");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
pipe.ds_ci_.depthBoundsTestEnable = VK_FALSE;
pipe.pipe_ms_state_ci_.alphaToOneEnable = VK_TRUE;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineMultisampleStateCreateInfo-alphaToOneEnable-00785");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
pipe.pipe_ms_state_ci_.alphaToOneEnable = VK_FALSE;
pipe.rs_state_ci_.depthClampEnable = VK_TRUE;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineRasterizationStateCreateInfo-depthClampEnable-00782");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativePipeline, MissingPipelineFormat) {
TEST_DESCRIPTION("Render with required pipeline formats VK_FORMAT_UNDEFINED");
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering_features = vku::InitStructHelper();
VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT unusued_attachment_features =
vku::InitStructHelper(&dynamic_rendering_features);
GetPhysicalDeviceFeatures2(unusued_attachment_features);
if (!dynamic_rendering_features.dynamicRendering) {
GTEST_SKIP() << "dynamicRendering not supported";
}
if (!unusued_attachment_features.dynamicRenderingUnusedAttachments) {
GTEST_SKIP() << "dynamicRenderingUnusedAttachments not supported";
}
RETURN_IF_SKIP(InitState(nullptr, &unusued_attachment_features));
VkFormat undefined = VK_FORMAT_UNDEFINED;
VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM;
VkFormat ds_format = FindSupportedDepthStencilFormat(gpu());
VkImageObj color_image(m_device);
color_image.Init(32, 32, 1, color_format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
VkImageView color_image_view = color_image.targetView(color_format);
VkImageObj ds_image(m_device);
ds_image.Init(32, 32, 1, ds_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
VkImageView ds_image_view = ds_image.targetView(ds_format, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
VkPipelineRenderingCreateInfoKHR pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 1u;
pipeline_rendering_info.pColorAttachmentFormats = &undefined;
pipeline_rendering_info.depthAttachmentFormat = ds_format;
pipeline_rendering_info.stencilAttachmentFormat = ds_format;
VkClearValue color_clear_value;
color_clear_value.color.float32[0] = 0.0f;
color_clear_value.color.float32[1] = 0.0f;
color_clear_value.color.float32[2] = 0.0f;
color_clear_value.color.float32[3] = 0.0f;
VkClearValue ds_clear_value;
ds_clear_value.depthStencil = {1.0f, 0u};
VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper();
color_attachment.imageView = color_image_view;
color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
color_attachment.clearValue = color_clear_value;
VkRenderingAttachmentInfo ds_attachment = vku::InitStructHelper();
ds_attachment.imageView = ds_image_view;
ds_attachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
ds_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
ds_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
ds_attachment.clearValue = ds_clear_value;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea = {{0, 0}, {32u, 32u}};
rendering_info.layerCount = 1u;
rendering_info.colorAttachmentCount = 1u;
rendering_info.pColorAttachments = &color_attachment;
rendering_info.pDepthAttachment = &ds_attachment;
rendering_info.pStencilAttachment = &ds_attachment;
VkPipelineColorBlendAttachmentState color_blend_attachment_state = {};
color_blend_attachment_state.blendEnable = VK_TRUE;
color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR;
color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD;
color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD;
color_blend_attachment_state.colorWriteMask =
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
VkPipelineDepthStencilStateCreateInfo ds_state = vku::InitStructHelper();
ds_state.depthTestEnable = VK_TRUE;
ds_state.depthWriteEnable = VK_TRUE;
ds_state.stencilTestEnable = VK_TRUE;
VkPipelineColorBlendStateCreateInfo color_blend_state = vku::InitStructHelper();
color_blend_state.attachmentCount = 1u;
color_blend_state.pAttachments = &color_blend_attachment_state;
CreatePipelineHelper color_pipe(*this);
color_pipe.InitState();
color_pipe.gp_ci_.pNext = &pipeline_rendering_info;
color_pipe.ds_ci_ = ds_state;
color_pipe.cb_ci_ = color_blend_state;
color_pipe.CreateGraphicsPipeline();
pipeline_rendering_info.pColorAttachmentFormats = &color_format;
pipeline_rendering_info.depthAttachmentFormat = undefined;
CreatePipelineHelper depth_pipe(*this);
depth_pipe.InitState();
depth_pipe.gp_ci_.pNext = &pipeline_rendering_info;
depth_pipe.ds_ci_ = ds_state;
color_pipe.cb_ci_ = color_blend_state;
depth_pipe.CreateGraphicsPipeline();
pipeline_rendering_info.depthAttachmentFormat = ds_format;
pipeline_rendering_info.stencilAttachmentFormat = undefined;
CreatePipelineHelper stencil_pipe(*this);
stencil_pipe.InitState();
stencil_pipe.gp_ci_.pNext = &pipeline_rendering_info;
stencil_pipe.ds_ci_ = ds_state;
color_pipe.cb_ci_ = color_blend_state;
stencil_pipe.CreateGraphicsPipeline();
m_commandBuffer->begin();
m_commandBuffer->BeginRendering(rendering_info);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, color_pipe.pipeline_);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-pColorAttachments-08963");
vk::CmdDraw(m_commandBuffer->handle(), 3u, 1u, 0u, 0u);
m_errorMonitor->VerifyFound();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, depth_pipe.pipeline_);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-pDepthAttachment-08964");
vk::CmdDraw(m_commandBuffer->handle(), 3u, 1u, 0u, 0u);
m_errorMonitor->VerifyFound();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, stencil_pipe.pipeline_);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-pStencilAttachment-08965");
vk::CmdDraw(m_commandBuffer->handle(), 3u, 1u, 0u, 0u);
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRendering();
m_commandBuffer->end();
}