blob: f6a52bba5abb1d8889881f4330ca88bdf45a3300 [file] [log] [blame]
/*
* Copyright (c) 2015-2025 The Khronos Group Inc.
* Copyright (c) 2015-2025 Valve Corporation
* Copyright (c) 2015-2025 LunarG, Inc.
* Copyright (c) 2015-2025 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
#include "../framework/descriptor_helper.h"
#include "../framework/render_pass_helper.h"
class PositivePipeline : public VkLayerTest {};
TEST_F(PositivePipeline, ComplexTypes) {
TEST_DESCRIPTION("Smoke test for complex types across VS/FS boundary");
AddRequiredFeature(vkt::Feature::tessellationShader);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj tcs(*m_device, kTessellationControlMinimalGlsl, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
VkShaderObj tes(*m_device, kTessellationEvalMinimalGlsl, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineInputAssemblyStateCreateInfo iasci{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0,
VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, VK_FALSE};
VkPipelineTessellationStateCreateInfo tsci{VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, nullptr, 0, 3};
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.pTessellationState = &tsci;
pipe.gp_ci_.pInputAssemblyState = &iasci;
pipe.shader_stages_ = {vs.GetStageCreateInfo(), tcs.GetStageCreateInfo(), tes.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, BasicUsage) {
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, MissingDescriptorUnused) {
TEST_DESCRIPTION(
"Test that pipeline validation accepts a compute pipeline which declares a descriptor-backed resource which is not "
"provided, but the shader does not statically use it. This is interesting because it requires compute pipelines to have a "
"proper descriptor use walk, which they didn't for some time.");
RETURN_IF_SKIP(Init());
const char *csSource = R"glsl(
#version 450
layout(local_size_x=1) in;
layout(set=0, binding=0) buffer block { vec4 x; };
void main(){
// x is not used.
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.CreateComputePipeline();
}
TEST_F(PositivePipeline, FragmentShadingRate) {
TEST_DESCRIPTION("Verify that pipeline validation accepts a compute pipeline with fragment shading rate extension enabled");
AddRequiredExtensions(VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::pipelineFragmentShadingRate);
AddRequiredFeature(vkt::Feature::primitiveFragmentShadingRate);
RETURN_IF_SKIP(Init());
const char *csSource = R"glsl(
#version 450
layout(local_size_x=1) in;
layout(set=0, binding=0) buffer block { vec4 x; };
void main(){
// x is not used.
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.CreateComputePipeline();
}
TEST_F(PositivePipeline, CombinedImageSamplerConsumedAsSampler) {
TEST_DESCRIPTION(
"Test that pipeline validation accepts a shader consuming only the sampler portion of a combined image + sampler");
RETURN_IF_SKIP(Init());
const char *csSource = R"glsl(
#version 450
layout(local_size_x=1) in;
layout(set=0, binding=0) uniform sampler s;
layout(set=0, binding=1) uniform texture2D t;
layout(set=0, binding=2) buffer block { vec4 x; };
void main() {
x = texture(sampler2D(t, s), vec2(0));
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.dsl_bindings_ = {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
};
pipe.cs_ = VkShaderObj(*m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.CreateComputePipeline();
}
TEST_F(PositivePipeline, CombinedImageSamplerConsumedAsImage) {
TEST_DESCRIPTION(
"Test that pipeline validation accepts a shader consuming only the image portion of a combined image + sampler");
RETURN_IF_SKIP(Init());
const char *csSource = R"glsl(
#version 450
layout(local_size_x=1) in;
layout(set=0, binding=0) uniform texture2D t;
layout(set=0, binding=1) uniform sampler s;
layout(set=0, binding=2) buffer block { vec4 x; };
void main() {
x = texture(sampler2D(t, s), vec2(0));
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.dsl_bindings_ = {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
};
pipe.cs_ = VkShaderObj(*m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.CreateComputePipeline();
}
TEST_F(PositivePipeline, CombinedImageSamplerConsumedAsBoth) {
TEST_DESCRIPTION(
"Test that pipeline validation accepts a shader consuming both the sampler and the image of a combined image+sampler but "
"via separate variables");
RETURN_IF_SKIP(Init());
const char *csSource = R"glsl(
#version 450
layout(local_size_x=1) in;
layout(set=0, binding=0) uniform texture2D t;
layout(set=0, binding=0) uniform sampler s; // both binding 0!
layout(set=0, binding=1) buffer block { vec4 x; };
void main() {
x = texture(sampler2D(t, s), vec2(0));
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.dsl_bindings_ = {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
};
pipe.cs_ = VkShaderObj(*m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.CreateComputePipeline();
}
TEST_F(PositivePipeline, IgnoredMultisampleState) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/5931");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const uint64_t fake_address_64 = 0xCDCDCDCDCDCDCDCD;
const uint64_t fake_address_32 = 0xCDCDCDCD;
void *bad_pointer = sizeof(void *) == 8 ? reinterpret_cast<void *>(fake_address_64) : reinterpret_cast<void *>(fake_address_32);
CreatePipelineHelper pipe(*this);
pipe.VertexShaderOnly();
pipe.rs_state_ci_.rasterizerDiscardEnable = VK_TRUE;
pipe.gp_ci_.pMultisampleState = reinterpret_cast<const VkPipelineMultisampleStateCreateInfo *>(bad_pointer);
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, CreateComputePipelineWithDerivatives) {
TEST_DESCRIPTION("Create Compute Pipeline with derivatives");
RETURN_IF_SKIP(Init());
const char *csSource = R"glsl(
#version 450
layout(local_size_x=2, local_size_y=4) in;
void main(){
}
)glsl";
VkShaderObj cs(*m_device, 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_infos[2];
compute_create_infos[0] = vku::InitStructHelper();
compute_create_infos[0].flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
compute_create_infos[0].stage = cs.GetStageCreateInfo();
compute_create_infos[0].layout = pipeline_layout;
compute_create_infos[0].basePipelineHandle = VK_NULL_HANDLE;
compute_create_infos[0].basePipelineIndex = -1;
compute_create_infos[1] = vku::InitStructHelper();
compute_create_infos[1].flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT;
compute_create_infos[1].stage = cs.GetStageCreateInfo();
compute_create_infos[1].layout = pipeline_layout;
// Base pipeline in pipelines[0], derivative in pipelines[1]
VkPipeline pipelines[2];
{
// Create a base pipeline and a derivative in a single call, using 0 as the base
compute_create_infos[1].basePipelineHandle = VK_NULL_HANDLE;
compute_create_infos[1].basePipelineIndex = 0;
vk::CreateComputePipelines(device(), VK_NULL_HANDLE, 2, compute_create_infos, nullptr, pipelines);
// Destroy the derivative pipeline
vk::DestroyPipeline(device(), pipelines[1], nullptr);
}
{
// Create a derivative pipeline, using base from previous call
compute_create_infos[1].basePipelineHandle = pipelines[0];
compute_create_infos[1].basePipelineIndex = -1;
vk::CreateComputePipelines(device(), VK_NULL_HANDLE, 1, &compute_create_infos[1], nullptr, &pipelines[1]);
}
for (auto pipeline : pipelines) {
vk::DestroyPipeline(device(), pipeline, nullptr);
}
}
TEST_F(PositivePipeline, CreateGraphicsPipelineWithIgnoredPointers) {
TEST_DESCRIPTION("Create Graphics Pipeline with pointers that must be ignored by layers");
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(Init());
m_depth_stencil_fmt = FindSupportedDepthStencilFormat(Gpu());
m_depthStencil->Init(*m_device, m_width, m_height, 1, m_depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
vkt::ImageView depth_image_view = m_depthStencil->CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
InitRenderTarget(&depth_image_view.handle());
const uint64_t fake_address_64 = 0xCDCDCDCDCDCDCDCD;
const uint64_t fake_address_32 = 0xCDCDCDCD;
void *hopefully_undereferencable_pointer =
sizeof(void *) == 8 ? reinterpret_cast<void *>(fake_address_64) : reinterpret_cast<void *>(fake_address_32);
VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineShaderStageCreateInfo stages[2] = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
const VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
nullptr, // pNext
0, // flags
0,
nullptr, // bindings
0,
nullptr // attributes
};
const VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
nullptr, // pNext
0, // flags
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
VK_FALSE // primitive restart
};
const VkPipelineRasterizationStateCreateInfo pipeline_rasterization_state_create_info_template{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
nullptr, // pNext
0, // flags
VK_FALSE, // depthClamp
VK_FALSE, // rasterizerDiscardEnable
VK_POLYGON_MODE_FILL,
VK_CULL_MODE_NONE,
VK_FRONT_FACE_COUNTER_CLOCKWISE,
VK_FALSE, // depthBias
0.0f,
0.0f,
0.0f, // depthBias params
1.0f // lineWidth
};
const VkPipelineMultisampleStateCreateInfo pipeline_multisample_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
nullptr, // pNext
0, // flags
VK_SAMPLE_COUNT_1_BIT,
VK_FALSE, // sample shading
0.0f, // minSampleShading
nullptr, // pSampleMask
VK_FALSE, // alphaToCoverageEnable
VK_FALSE // alphaToOneEnable
};
vkt::PipelineLayout pipeline_layout;
{
VkPipelineLayoutCreateInfo pipeline_layout_create_info{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
nullptr, // pNext
0, // flags
0,
nullptr, // layouts
0,
nullptr // push constants
};
pipeline_layout.Init(*m_device, pipeline_layout_create_info, {});
}
// try disabled rasterizer and no tessellation
{
VkPipelineRasterizationStateCreateInfo pipeline_rasterization_state_create_info =
pipeline_rasterization_state_create_info_template;
pipeline_rasterization_state_create_info.rasterizerDiscardEnable = VK_TRUE;
// If rasterizer is disabled, fragment shader state must not be present.
VkGraphicsPipelineCreateInfo graphics_pipeline_create_info{
VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
nullptr, // pNext
0, // flags
1, // stageCount
stages,
&pipeline_vertex_input_state_create_info,
&pipeline_input_assembly_state_create_info,
reinterpret_cast<const VkPipelineTessellationStateCreateInfo *>(hopefully_undereferencable_pointer),
reinterpret_cast<const VkPipelineViewportStateCreateInfo *>(hopefully_undereferencable_pointer),
&pipeline_rasterization_state_create_info,
&pipeline_multisample_state_create_info,
reinterpret_cast<const VkPipelineDepthStencilStateCreateInfo *>(hopefully_undereferencable_pointer),
reinterpret_cast<const VkPipelineColorBlendStateCreateInfo *>(hopefully_undereferencable_pointer),
nullptr, // dynamic states
pipeline_layout,
m_renderPass,
0, // subpass
VK_NULL_HANDLE,
0};
vkt::Pipeline pipeline(*m_device, graphics_pipeline_create_info);
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
}
// try enabled rasterizer but no subpass attachments
{
VkPipelineRasterizationStateCreateInfo pipeline_rasterization_state_create_info =
pipeline_rasterization_state_create_info_template;
pipeline_rasterization_state_create_info.rasterizerDiscardEnable = VK_FALSE;
VkViewport viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
VkRect2D scissor = {{0, 0}, {m_width, m_height}};
const VkPipelineViewportStateCreateInfo pipeline_viewport_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
nullptr, // pNext
0, // flags
1,
&viewport,
1,
&scissor};
vkt::RenderPass render_pass;
{
VkSubpassDescription subpass_desc = {};
VkRenderPassCreateInfo render_pass_create_info{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr, // pNext
0, // flags
0,
nullptr, // attachments
1,
&subpass_desc,
0,
nullptr // subpass dependencies
};
render_pass.Init(*m_device, render_pass_create_info);
}
VkGraphicsPipelineCreateInfo graphics_pipeline_create_info{
VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
nullptr, // pNext
0, // flags
size32(stages), // stageCount
stages,
&pipeline_vertex_input_state_create_info,
&pipeline_input_assembly_state_create_info,
nullptr,
&pipeline_viewport_state_create_info,
&pipeline_rasterization_state_create_info,
&pipeline_multisample_state_create_info,
reinterpret_cast<const VkPipelineDepthStencilStateCreateInfo *>(hopefully_undereferencable_pointer),
reinterpret_cast<const VkPipelineColorBlendStateCreateInfo *>(hopefully_undereferencable_pointer),
nullptr, // dynamic states
pipeline_layout,
render_pass,
0, // subpass
VK_NULL_HANDLE,
0};
vkt::Pipeline pipeline(*m_device, graphics_pipeline_create_info);
}
// try dynamic viewport and scissor
{
VkPipelineRasterizationStateCreateInfo pipeline_rasterization_state_create_info =
pipeline_rasterization_state_create_info_template;
pipeline_rasterization_state_create_info.rasterizerDiscardEnable = VK_FALSE;
const VkPipelineViewportStateCreateInfo pipeline_viewport_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
nullptr, // pNext
0, // flags
1,
reinterpret_cast<const VkViewport *>(hopefully_undereferencable_pointer),
1,
reinterpret_cast<const VkRect2D *>(hopefully_undereferencable_pointer)};
const VkPipelineDepthStencilStateCreateInfo pipeline_depth_stencil_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
nullptr, // pNext
0, // flags
};
const VkPipelineColorBlendAttachmentState pipeline_color_blend_attachment_state = {};
const VkPipelineColorBlendStateCreateInfo pipeline_color_blend_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
nullptr, // pNext
0, // flags
VK_FALSE,
VK_LOGIC_OP_CLEAR,
1,
&pipeline_color_blend_attachment_state,
{0.0f, 0.0f, 0.0f, 0.0f}};
const VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
const VkPipelineDynamicStateCreateInfo pipeline_dynamic_state_create_info{
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
nullptr, // pNext
0, // flags
2, dynamic_states};
VkGraphicsPipelineCreateInfo graphics_pipeline_create_info{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
nullptr, // pNext
0, // flags
size32(stages), // stageCount
stages,
&pipeline_vertex_input_state_create_info,
&pipeline_input_assembly_state_create_info,
nullptr,
&pipeline_viewport_state_create_info,
&pipeline_rasterization_state_create_info,
&pipeline_multisample_state_create_info,
&pipeline_depth_stencil_state_create_info,
&pipeline_color_blend_state_create_info,
&pipeline_dynamic_state_create_info, // dynamic states
pipeline_layout,
m_renderPass,
0, // subpass
VK_NULL_HANDLE,
0};
vkt::Pipeline pipeline(*m_device, graphics_pipeline_create_info);
}
}
TEST_F(PositivePipeline, CoreChecksDisabled) {
TEST_DESCRIPTION("Test CreatePipeline while the CoreChecks validation object is disabled");
AddRequiredExtensions(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME);
// Enable KHR validation features extension
VkValidationFeatureDisableEXT disables[] = {VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT};
VkValidationFeaturesEXT features = vku::InitStructHelper();
features.disabledValidationFeatureCount = 1;
features.pDisabledValidationFeatures = disables;
RETURN_IF_SKIP(Init(nullptr, nullptr, &features));
InitRenderTarget();
VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineInputAssemblyStateCreateInfo iasci{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0,
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE};
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.pInputAssemblyState = &iasci;
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, TessellationDomainOrigin) {
TEST_DESCRIPTION(
"Test CreatePipeline when VkPipelineTessellationStateCreateInfo.pNext include "
"VkPipelineTessellationDomainOriginStateCreateInfo");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::tessellationShader);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj tcs(*m_device, kTessellationControlMinimalGlsl, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
VkShaderObj tes(*m_device, kTessellationEvalMinimalGlsl, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineInputAssemblyStateCreateInfo iasci{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0,
VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, VK_FALSE};
VkPipelineTessellationDomainOriginStateCreateInfo tessellationDomainOriginStateInfo = {
VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, VK_NULL_HANDLE,
VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT};
VkPipelineTessellationStateCreateInfo tsci{VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
&tessellationDomainOriginStateInfo, 0, 3};
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.pTessellationState = &tsci;
pipe.gp_ci_.pInputAssemblyState = &iasci;
pipe.shader_stages_ = {vs.GetStageCreateInfo(), tcs.GetStageCreateInfo(), tes.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, ViewportArray2NV) {
TEST_DESCRIPTION("Test to validate VK_NV_viewport_array2");
AddRequiredExtensions(VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::multiViewport);
AddRequiredFeature(vkt::Feature::tessellationShader);
AddRequiredFeature(vkt::Feature::geometryShader);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char tcs_src[] = R"glsl(
#version 450
layout(vertices = 3) out;
void main() {
gl_TessLevelOuter[0] = 4.0f;
gl_TessLevelOuter[1] = 4.0f;
gl_TessLevelOuter[2] = 4.0f;
gl_TessLevelInner[0] = 3.0f;
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
)glsl";
// Create tessellation control and fragment shader here since they will not be
// modified by the different test cases.
VkShaderObj tcs(*m_device, tcs_src, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
const float fp_width = static_cast<float>(m_width);
const float fp_height = static_cast<float>(m_height);
std::vector<VkViewport> vps = {{0.0f, 0.0f, fp_width / 2.0f, fp_height}, {fp_width / 2.0f, 0.0f, fp_width / 2.0f, fp_height}};
std::vector<VkRect2D> scs = {{{0, 0}, {m_width / 2, m_height}},
{{static_cast<int32_t>(m_width) / 2, 0}, {m_width / 2, m_height}}};
enum class TestStage { VERTEX = 0, TESSELLATION_EVAL = 1, GEOMETRY = 2 };
std::array<TestStage, 3> vertex_stages = {{TestStage::VERTEX, TestStage::TESSELLATION_EVAL, TestStage::GEOMETRY}};
// Verify that the usage of gl_ViewportMask[] in the allowed vertex processing
// stages does not cause any errors.
for (auto stage : vertex_stages) {
CreatePipelineHelper pipe(*this);
pipe.ia_ci_.topology =
(stage != TestStage::VERTEX) ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
pipe.shader_stages_.clear();
std::ostringstream vs_src, tes_src, geom_src;
vs_src << R"(
#version 450
#extension GL_NV_viewport_array2 : require
vec2 positions[3] = { vec2( 0.0f, -0.5f),
vec2( 0.5f, 0.5f),
vec2(-0.5f, 0.5f)
};
void main() {)";
// Write viewportMask if the vertex shader is the last vertex processing stage.
if (stage == TestStage::VERTEX) {
vs_src << "gl_ViewportMask[0] = 3;\n";
}
vs_src << R"(
gl_Position = vec4(positions[gl_VertexIndex % 3], 0.0, 1.0);
})";
VkShaderObj vs(*m_device, vs_src.str().c_str(), VK_SHADER_STAGE_VERTEX_BIT);
pipe.shader_stages_.push_back(vs.GetStageCreateInfo());
std::unique_ptr<VkShaderObj> tes, geom;
if (stage >= TestStage::TESSELLATION_EVAL) {
tes_src << R"(
#version 450
#extension GL_NV_viewport_array2 : require
layout(triangles) in;
void main() {
gl_Position = (gl_in[0].gl_Position * gl_TessCoord.x +
gl_in[1].gl_Position * gl_TessCoord.y +
gl_in[2].gl_Position * gl_TessCoord.z);)";
// Write viewportMask if the tess eval shader is the last vertex processing stage.
if (stage == TestStage::TESSELLATION_EVAL) {
tes_src << "gl_ViewportMask[0] = 3;\n";
}
tes_src << "}";
tes = std::make_unique<VkShaderObj>(*m_device, tes_src.str().c_str(), VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
pipe.shader_stages_.push_back(tes.get()->GetStageCreateInfo());
pipe.shader_stages_.push_back(tcs.GetStageCreateInfo());
pipe.tess_ci_ = vku::InitStructHelper();
pipe.tess_ci_.patchControlPoints = 3;
}
if (stage >= TestStage::GEOMETRY) {
geom_src << R"(
#version 450
#extension GL_NV_viewport_array2 : require
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
void main() {
gl_ViewportMask[0] = 3;
for(int i = 0; i < 3; ++i) {
gl_Position = gl_in[i].gl_Position;
EmitVertex();
}
})";
geom = std::make_unique<VkShaderObj>(*m_device, geom_src.str().c_str(), VK_SHADER_STAGE_GEOMETRY_BIT);
pipe.shader_stages_.push_back(geom.get()->GetStageCreateInfo());
}
pipe.shader_stages_.push_back(fs.GetStageCreateInfo());
pipe.CreateGraphicsPipeline();
}
}
TEST_F(PositivePipeline, AttachmentUnused) {
TEST_DESCRIPTION("Make sure unused attachments are correctly ignored.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *fsSource = R"glsl(
#version 450
layout(location=0) out vec4 x;
void main(){
x = vec4(1); // attachment is unused
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
VkAttachmentReference const color_attachments[1]{{VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
VkSubpassDescription const subpass_descriptions[1]{
{0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, color_attachments, nullptr, nullptr, 0, nullptr}};
VkAttachmentDescription const attachment_descriptions[1]{{0, VK_FORMAT_B8G8R8A8_UNORM, VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
VkRenderPassCreateInfo const render_pass_info{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, attachment_descriptions, 1, subpass_descriptions, 0, nullptr};
vkt::RenderPass render_pass(*m_device, render_pass_info);
const auto override_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
helper.gp_ci_.renderPass = render_pass;
};
CreatePipelineHelper::OneshotTest(*this, override_info, kErrorBit);
}
TEST_F(PositivePipeline, SampleMaskOverrideCoverageNV) {
TEST_DESCRIPTION("Test to validate VK_NV_sample_mask_override_coverage");
AddRequiredExtensions(VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const char vs_src[] = R"glsl(
#version 450
layout(location=0) out vec4 fragColor;
const vec2 pos[3] = { vec2( 0.0f, -0.5f),
vec2( 0.5f, 0.5f),
vec2(-0.5f, 0.5f)
};
void main()
{
gl_Position = vec4(pos[gl_VertexIndex % 3], 0.0f, 1.0f);
fragColor = vec4(0.0f, 1.0f, 0.0f, 1.0f);
}
)glsl";
const char fs_src[] = R"glsl(
#version 450
#extension GL_NV_sample_mask_override_coverage : require
layout(location = 0) in vec4 fragColor;
layout(location = 0) out vec4 outColor;
layout(override_coverage) out int gl_SampleMask[];
void main()
{
gl_SampleMask[0] = 0xff;
outColor = fragColor;
}
)glsl";
const VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_8_BIT;
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_B8G8R8A8_UNORM, sampleCount, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddColorAttachment(0);
rp.CreateRenderPass();
const vkt::PipelineLayout pl(*m_device);
VkSampleMask sampleMask = 0x01;
VkPipelineMultisampleStateCreateInfo msaa = vku::InitStructHelper();
msaa.rasterizationSamples = sampleCount;
msaa.sampleShadingEnable = VK_FALSE;
msaa.pSampleMask = &sampleMask;
VkShaderObj vs(*m_device, vs_src, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fs_src, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.layout = pl;
pipe.gp_ci_.renderPass = rp;
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.pMultisampleState = &msaa;
// Create pipeline and make sure that the usage of NV_sample_mask_override_coverage
// in the fragment shader does not cause any errors.
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, RasterizationDiscardEnableTrue) {
TEST_DESCRIPTION("Ensure it doesn't crash and trigger error msg when rasterizerDiscardEnable = true");
RETURN_IF_SKIP(Init());
InitRenderTarget();
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddColorAttachment(0);
rp.CreateRenderPass();
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.pViewportState = nullptr;
pipe.gp_ci_.pMultisampleState = nullptr;
pipe.gp_ci_.pDepthStencilState = nullptr;
pipe.gp_ci_.pColorBlendState = nullptr;
pipe.gp_ci_.renderPass = rp;
// When rasterizer discard is enabled, fragment shader state must not be present.
pipe.VertexShaderOnly();
// Skip the test in NexusPlayer. The driver crashes when pViewportState, pMultisampleState, pDepthStencilState, pColorBlendState
// are NULL.
pipe.rs_state_ci_.rasterizerDiscardEnable = VK_TRUE;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, SamplerDataForCombinedImageSampler) {
TEST_DESCRIPTION("Shader code uses sampler data for CombinedImageSampler");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *fsSource = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpDecorate %InputData DescriptorSet 0
OpDecorate %InputData Binding 0
OpDecorate %SamplerData DescriptorSet 0
OpDecorate %SamplerData Binding 0
%void = OpTypeVoid
%f32 = OpTypeFloat 32
%Image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f
%ImagePtr = OpTypePointer UniformConstant %Image
%InputData = OpVariable %ImagePtr UniformConstant
%Sampler = OpTypeSampler
%SamplerPtr = OpTypePointer UniformConstant %Sampler
%SamplerData = OpVariable %SamplerPtr UniformConstant
%SampledImage = OpTypeSampledImage %Image
%func = OpTypeFunction %void
%main = OpFunction %void None %func
%40 = OpLabel
%call_smp = OpLoad %Sampler %SamplerData
OpReturn
OpFunctionEnd)";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM);
CreatePipelineHelper pipe(*this);
pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr};
pipe.shader_stages_ = {fs.GetStageCreateInfo(), pipe.vs_->GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::ImageView view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
pipe.descriptor_set_->WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
pipe.descriptor_set_->UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1,
&pipe.descriptor_set_->set_, 0, NULL);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositivePipeline, ConditionalRendering) {
TEST_DESCRIPTION("Create renderpass and CmdPipelineBarrier with VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT");
AddRequiredExtensions(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::conditionalRendering);
RETURN_IF_SKIP(Init());
InitRenderTarget();
// A renderpass with a single subpass that declared a self-dependency
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddColorAttachment(0);
rp.AddSubpassDependency(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT,
VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT, 0);
rp.CreateRenderPass();
vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView imageView = image.CreateView();
vkt::Framebuffer fb(*m_device, rp, 1, &imageView.handle());
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(rp, fb, 32, 32);
VkImageMemoryBarrier imb = vku::InitStructHelper();
imb.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imb.dstAccessMask = VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT;
imb.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imb.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imb.image = image;
imb.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT,
0, 0, nullptr, 0, nullptr, 1, &imb);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositivePipeline, ShaderTileImageColor) {
TEST_DESCRIPTION("Create 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);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::shaderTileImageColorReadAccess);
AddRequiredFeature(vkt::Feature::sampleRateShading);
RETURN_IF_SKIP(Init());
VkFormat depth_format = VK_FORMAT_D32_SFLOAT_S8_UINT;
VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM;
VkPipelineRenderingCreateInfo 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();
VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
auto fs = VkShaderObj::CreateFromASM(this, kShaderTileImageColorReadSpv, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineMultisampleStateCreateInfo ms_ci = vku::InitStructHelper();
ms_ci.sampleShadingEnable = VK_TRUE;
ms_ci.minSampleShading = 1.0;
ms_ci.rasterizationSamples = VK_SAMPLE_COUNT_4_BIT;
CreatePipelineHelper ms_pipeline(*this, &pipeline_rendering_info);
ms_pipeline.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
ms_pipeline.gp_ci_.renderPass = VK_NULL_HANDLE;
ms_pipeline.gp_ci_.pDepthStencilState = &ds_ci;
ms_pipeline.gp_ci_.pMultisampleState = &ms_ci;
ms_pipeline.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, ShaderTileImageDepth) {
TEST_DESCRIPTION("Create 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);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::shaderTileImageDepthReadAccess);
RETURN_IF_SKIP(Init());
VkFormat depth_format = VK_FORMAT_D32_SFLOAT_S8_UINT;
VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM;
VkPipelineRenderingCreateInfo 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();
VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
auto fs = VkShaderObj::CreateFromASM(this, kShaderTileImageDepthReadSpv, VK_SHADER_STAGE_FRAGMENT_BIT);
ds_ci.depthWriteEnable = false;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.renderPass = VK_NULL_HANDLE;
pipe.gp_ci_.pDepthStencilState = &ds_ci;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, ShaderTileImageStencil) {
TEST_DESCRIPTION("Create 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);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::shaderTileImageStencilReadAccess);
RETURN_IF_SKIP(Init());
VkFormat depth_format = VK_FORMAT_D32_SFLOAT_S8_UINT;
VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM;
VkPipelineRenderingCreateInfo 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();
VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
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 = 0;
stencil_state.reference = 0xf;
ds_ci = {};
ds_ci.front = stencil_state;
ds_ci.back = stencil_state;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.renderPass = VK_NULL_HANDLE;
pipe.gp_ci_.pDepthStencilState = &ds_ci;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, PervertexNVShaderAttributes) {
TEST_DESCRIPTION("Test using TestRasterizationStateStreamCreateInfoEXT with invalid rasterizationStream.");
AddRequiredExtensions(VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework());
VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV fragment_shader_barycentric_features = vku::InitStructHelper();
fragment_shader_barycentric_features.fragmentShaderBarycentric = VK_TRUE;
VkPhysicalDeviceFeatures2KHR features2 = vku::InitStructHelper(&fragment_shader_barycentric_features);
RETURN_IF_SKIP(InitState(nullptr, &features2));
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
layout(location = 0) out PerVertex {
vec3 vtxPos;
} outputs;
vec2 triangle_positions[3] = vec2[](
vec2(0.5, -0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.5)
);
void main() {
gl_Position = vec4(triangle_positions[gl_VertexIndex], 0.0, 1.0);
outputs.vtxPos = gl_Position.xyz;
}
)glsl";
const char *fsSource = R"glsl(
#version 450
#extension GL_NV_fragment_shader_barycentric : enable
layout(location = 0) in pervertexNV PerVertex {
vec3 vtxPos;
} inputs[3];
layout(location = 0) out vec4 out_color;
void main() {
vec3 b = gl_BaryCoordNV;
if (b.x > b.y && b.x > b.z) {
out_color = vec4(inputs[0].vtxPos, 1.0);
}
else if(b.y > b.z) {
out_color = vec4(inputs[1].vtxPos, 1.0);
}
else {
out_color = vec4(inputs[2].vtxPos, 1.0);
}
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, MutableStorageImageFormatWriteForFormat) {
TEST_DESCRIPTION("Create a shader writing a storage image without an image format");
// need to be compatible to use VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
const VkFormat image_format = VK_FORMAT_B8G8R8A8_SRGB;
const VkFormat image_view_format = VK_FORMAT_R32_SFLOAT;
AddRequiredExtensions(VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
PFN_vkSetPhysicalDeviceFormatProperties2EXT fpvkSetPhysicalDeviceFormatProperties2EXT = nullptr;
PFN_vkGetOriginalPhysicalDeviceFormatProperties2EXT fpvkGetOriginalPhysicalDeviceFormatProperties2EXT = nullptr;
if (!LoadDeviceProfileLayer(fpvkSetPhysicalDeviceFormatProperties2EXT, fpvkGetOriginalPhysicalDeviceFormatProperties2EXT)) {
GTEST_SKIP() << "Failed to load device profile layer.";
}
VkFormatProperties3 fmt_props_3 = vku::InitStructHelper();
VkFormatProperties2 fmt_props = vku::InitStructHelper(&fmt_props_3);
fpvkGetOriginalPhysicalDeviceFormatProperties2EXT(Gpu(), image_format, &fmt_props);
fmt_props.formatProperties.optimalTilingFeatures =
(fmt_props.formatProperties.optimalTilingFeatures & ~VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT);
fmt_props_3.optimalTilingFeatures = (fmt_props_3.optimalTilingFeatures & ~VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT);
fmt_props_3.optimalTilingFeatures = (fmt_props_3.optimalTilingFeatures & ~VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT);
fpvkSetPhysicalDeviceFormatProperties2EXT(Gpu(), image_format, fmt_props);
fpvkGetOriginalPhysicalDeviceFormatProperties2EXT(Gpu(), image_view_format, &fmt_props);
fmt_props.formatProperties.optimalTilingFeatures |= VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT;
fmt_props_3.optimalTilingFeatures |= VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT;
fmt_props_3.optimalTilingFeatures |= VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT;
fpvkSetPhysicalDeviceFormatProperties2EXT(Gpu(), image_view_format, fmt_props);
// Make sure compute pipeline has a compute shader stage set
const char *csSource = R"(
OpCapability Shader
OpCapability StorageImageWriteWithoutFormat
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource GLSL 450
OpName %main "main"
OpName %img "img"
OpDecorate %img DescriptorSet 0
OpDecorate %img Binding 0
OpDecorate %img NonWritable
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%7 = OpTypeImage %float 2D 0 0 0 2 Unknown
%_ptr_UniformConstant_7 = OpTypePointer UniformConstant %7
%img = OpVariable %_ptr_UniformConstant_7 UniformConstant
%int = OpTypeInt 32 1
%v2int = OpTypeVector %int 2
%int_0 = OpConstant %int 0
%14 = OpConstantComposite %v2int %int_0 %int_0
%v4float = OpTypeVector %float 4
%float_0 = OpConstant %float 0
%17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%uint = OpTypeInt 32 0
%v3uint = OpTypeVector %uint 3
%uint_1 = OpConstant %uint 1
%main = OpFunction %void None %3
%5 = OpLabel
%10 = OpLoad %7 %img
OpImageWrite %10 %14 %17
OpReturn
OpFunctionEnd
)";
OneOffDescriptorSet ds(m_device, {
{0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
});
CreateComputePipelineHelper cs_pipeline(*this);
cs_pipeline.cs_ = VkShaderObj(*m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM);
cs_pipeline.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&ds.layout_});
cs_pipeline.LateBindPipelineInfo();
cs_pipeline.cp_ci_.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; // override with wrong value
cs_pipeline.CreateComputePipeline(false); // need false to prevent late binding
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = image_format;
image_create_info.extent = {32, 32, 1};
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_STORAGE_BIT;
VkImageFormatProperties format_props;
if (VK_SUCCESS != GetImageFormatProps(Gpu(), image_create_info, format_props)) {
GTEST_SKIP() << "Device will not be able to initialize buffer view skipped";
}
vkt::Image image(*m_device, image_create_info, vkt::set_layout);
vkt::ImageView view = image.CreateView();
ds.WriteDescriptorImageInfo(0, view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_LAYOUT_GENERAL);
ds.UpdateDescriptorSets();
m_command_buffer.Reset();
m_command_buffer.Begin();
VkImageMemoryBarrier img_barrier = vku::InitStructHelper();
img_barrier.srcAccessMask = VK_ACCESS_HOST_READ_BIT;
img_barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
img_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
img_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
img_barrier.image = image; // Image mis-matches with FB image
img_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0,
nullptr, 1, &img_barrier);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cs_pipeline);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cs_pipeline.pipeline_layout_, 0, 1, &ds.set_, 0,
nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
}
TEST_F(PositivePipeline, CreateGraphicsPipelineRasterizationOrderAttachmentAccessFlags) {
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;
};
// Color attachment
if (rasterization_order_features.rasterizationOrderColorAttachmentAccess) {
cb_ci.flags = VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT;
ds_ci.flags = 0;
vkt::RenderPass render_pass;
create_render_pass(VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT, render_pass);
render_pass_handle = render_pass;
CreatePipelineHelper::OneshotTest(*this, set_flgas_pipeline_createinfo, kErrorBit);
}
// 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_EXT;
vkt::RenderPass render_pass;
create_render_pass(VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT, render_pass);
render_pass_handle = render_pass;
CreatePipelineHelper::OneshotTest(*this, set_flgas_pipeline_createinfo, kErrorBit);
}
// 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_EXT;
vkt::RenderPass render_pass;
create_render_pass(VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT, render_pass);
render_pass_handle = render_pass;
CreatePipelineHelper::OneshotTest(*this, set_flgas_pipeline_createinfo, kErrorBit);
}
}
TEST_F(PositivePipeline, AttachmentsDisableRasterization) {
TEST_DESCRIPTION(
"Create a pipeline with rasterization disabled, containing a valid pColorBlendState and color attachments, "
"without a fragment shader");
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.rs_state_ci_.rasterizerDiscardEnable = VK_TRUE;
// Rasterization discard enable prohibits fragment shader.
pipe.VertexShaderOnly();
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, DualBlendShader) {
TEST_DESCRIPTION("Test drawing with dual source blending with too many fragment output attachments.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::dualSrcBlend);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *fsSource = R"glsl(
#version 450
layout(location = 0, index = 0) out vec4 c1;
layout(location = 0, index = 1) out vec4 c2;
void main(){
c1 = vec4(0.5f);
c2 = vec4(0.5f);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineColorBlendAttachmentState 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 pipe(*this);
pipe.cb_attachments_ = cb_attachments;
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
// CTS was written, but may fail on older drivers
// https://gitlab.khronos.org/Tracker/vk-gl-cts/-/issues/3736
TEST_F(PositivePipeline, CreationFeedbackCount0) {
TEST_DESCRIPTION("Test graphics pipeline feedback stage count check with 0.");
AddRequiredExtensions(VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkPipelineCreationFeedbackCreateInfo feedback_info = vku::InitStructHelper();
VkPipelineCreationFeedback feedbacks[1] = {};
// 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 = 0;
auto set_feedback = [&feedback_info](CreatePipelineHelper &helper) { helper.gp_ci_.pNext = &feedback_info; };
CreatePipelineHelper::OneshotTest(*this, set_feedback, kErrorBit);
}
TEST_F(PositivePipeline, ShaderModuleIdentifier) {
TEST_DESCRIPTION("Create a pipeline using a shader module identifier");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::pipelineCreationCacheControl);
AddRequiredFeature(vkt::Feature::shaderModuleIdentifier);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkPipelineShaderStageModuleIdentifierCreateInfoEXT sm_id_create_info = vku::InitStructHelper();
VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderModuleIdentifierEXT get_identifier = vku::InitStructHelper();
vk::GetShaderModuleIdentifierEXT(device(), vs, &get_identifier);
sm_id_create_info.identifierSize = get_identifier.identifierSize;
sm_id_create_info.pIdentifier = get_identifier.identifier;
VkPipelineShaderStageCreateInfo stage_ci = vku::InitStructHelper(&sm_id_create_info);
stage_ci.stage = VK_SHADER_STAGE_VERTEX_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.stageCount = 1;
pipe.gp_ci_.pStages = &stage_ci;
pipe.gp_ci_.flags = VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
pipe.rs_state_ci_.rasterizerDiscardEnable = VK_TRUE;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, ViewportSwizzleNV) {
AddRequiredExtensions(VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::multiViewport);
RETURN_IF_SKIP(Init());
InitRenderTarget();
std::array<VkViewportSwizzleNV, 2> swizzle = {};
swizzle.fill({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});
std::array<VkViewport, 2> viewports = {};
std::array<VkRect2D, 2> scissors = {};
viewports.fill({0, 0, 16, 16, 0, 1});
scissors.fill({{0, 0}, {16, 16}});
// Test case where VkPipelineViewportSwizzleStateCreateInfoNV::viewportCount is EQUAL TO viewportCount set in
// VkPipelineViewportStateCreateInfo
{
VkPipelineViewportSwizzleStateCreateInfoNV vp_swizzle_state = vku::InitStructHelper();
vp_swizzle_state.viewportCount = size32(viewports);
vp_swizzle_state.pViewportSwizzles = swizzle.data();
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);
}
// Test case where VkPipelineViewportSwizzleStateCreateInfoNV::viewportCount is GREATER THAN viewportCount set in
// VkPipelineViewportStateCreateInfo
{
VkPipelineViewportSwizzleStateCreateInfoNV vp_swizzle_state = vku::InitStructHelper();
vp_swizzle_state.viewportCount = size32(viewports);
vp_swizzle_state.pViewportSwizzles = swizzle.data();
auto break_vp_count = [&vp_swizzle_state, &viewports, &scissors](CreatePipelineHelper &helper) {
helper.vp_state_ci_.viewportCount = 1;
helper.vp_state_ci_.pViewports = viewports.data();
helper.vp_state_ci_.scissorCount = 1;
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);
}
}
TEST_F(PositivePipeline, RasterStateWithDepthBiasRepresentationInfo) {
TEST_DESCRIPTION("VkDepthBiasRepresentationInfoEXT in VkPipelineRasterizationStateCreateInfo pNext chain");
AddRequiredExtensions(VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::depthBiasControl);
AddRequiredFeature(vkt::Feature::leastRepresentableValueForceUnormRepresentation);
AddRequiredFeature(vkt::Feature::floatRepresentation);
AddRequiredFeature(vkt::Feature::depthBiasExact);
// Make sure validation of VkDepthBiasRepresentationInfoEXT in VkPipelineRasterizationStateCreateInfo does not rely on
// depthBiasClamp being enabled
RETURN_IF_SKIP(Init());
InitRenderTarget();
const auto create_pipe_with_depth_bias_representation = [this](VkDepthBiasRepresentationInfoEXT &depth_bias_representation) {
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS);
pipe.rs_state_ci_.pNext = &depth_bias_representation;
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;
create_pipe_with_depth_bias_representation(depth_bias_representation);
depth_bias_representation.depthBiasRepresentation = VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT;
create_pipe_with_depth_bias_representation(depth_bias_representation);
}
TEST_F(PositivePipeline, DeviceGeneratedCommands) {
TEST_DESCRIPTION("Test creating pipeline with device generated commands");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_NV_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework());
VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV dgc_features = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(dgc_features);
RETURN_IF_SKIP(InitState(nullptr, &features2));
InitRenderTarget();
if (!dgc_features.deviceGeneratedCommands) {
GTEST_SKIP() << "deviceGeneratedCommands not supported";
}
VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineShaderStageCreateInfo stages[2] = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
VkPipelineVertexInputStateCreateInfo vertex_input_state = vku::InitStructHelper();
VkPipelineTessellationStateCreateInfo tessellation_state = vku::InitStructHelper();
VkGraphicsShaderGroupCreateInfoNV group = vku::InitStructHelper();
group.stageCount = 2u;
group.pStages = stages;
group.pVertexInputState = &vertex_input_state;
group.pTessellationState = &tessellation_state;
VkGraphicsPipelineShaderGroupsCreateInfoNV shader_groups_ci = vku::InitStructHelper();
shader_groups_ci.groupCount = 1u;
shader_groups_ci.pGroups = &group;
shader_groups_ci.pipelineCount = 0u;
shader_groups_ci.pPipelines = nullptr;
CreatePipelineHelper pipe(*this, &shader_groups_ci);
pipe.shader_stages_ = {stages[0], stages[1]};
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, DepthStencilStateIgnored) {
TEST_DESCRIPTION("Have a valid null pDepthStencilState with a Depth attachment");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
RETURN_IF_SKIP(Init());
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentDescription(VK_FORMAT_D16_UNORM, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddAttachmentReference({1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL});
rp.AddColorAttachment(0);
rp.AddDepthStencilAttachment(1);
rp.CreateRenderPass();
// disable with rasterizerDiscardEnable
{
CreatePipelineHelper pipe(*this);
pipe.VertexShaderOnly();
pipe.rs_state_ci_.rasterizerDiscardEnable = VK_TRUE;
pipe.gp_ci_.renderPass = rp;
pipe.CreateGraphicsPipeline();
}
// disable with dynamic state
{
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_COMPARE_OP);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_STENCIL_OP);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
pipe.gp_ci_.renderPass = rp;
pipe.CreateGraphicsPipeline();
}
}
TEST_F(PositivePipeline, ViewportStateNotSet) {
TEST_DESCRIPTION("Create pipeline with viewport state not set");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
AddRequiredFeature(vkt::Feature::extendedDynamicState2);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE);
pipe.gp_ci_.pViewportState = nullptr;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, ViewportStateNotSetRasterizerDiscardEnabled) {
TEST_DESCRIPTION("Create pipeline with viewport state not set");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
AddRequiredFeature(vkt::Feature::extendedDynamicState2);
AddRequiredFeature(vkt::Feature::sampleRateShading);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkPipelineRasterizationStateCreateInfo rasterization_state = vku::InitStructHelper();
rasterization_state.rasterizerDiscardEnable = VK_TRUE;
rasterization_state.polygonMode = VK_POLYGON_MODE_FILL;
rasterization_state.cullMode = VK_CULL_MODE_NONE;
rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterization_state.lineWidth = 1.0f;
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT);
pipe.gp_ci_.pRasterizationState = &rasterization_state;
pipe.gp_ci_.pViewportState = nullptr;
pipe.VertexShaderOnly();
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, InterpolateAtSample) {
TEST_DESCRIPTION("Test using spirv instruction InterpolateAtSample");
AddRequiredFeature(vkt::Feature::sampleRateShading);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char vs_src[] = R"glsl(
#version 460
layout(location = 0) out vec2 uv;
void main() {
uv = vec2(gl_VertexIndex & 1, (gl_VertexIndex >> 1) & 1);
gl_Position = vec4(uv, 0.0f, 1.0f);
}
)glsl";
const char fs_src[] = R"glsl(
#version 460
layout(location = 0) out vec4 uFragColor;
layout(location = 0) in vec2 v;
void main() {
vec2 sample1 = interpolateAtSample(v, 0);
uFragColor = vec4(0.1f);
}
)glsl";
VkShaderObj vs(*m_device, vs_src, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fs_src, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(m_command_buffer, 3u, 1u, 0u, 0u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositivePipeline, ShaderModuleIdentifierZeroLength) {
TEST_DESCRIPTION("Use shader module identifier with zero size and provide a shader module");
AddRequiredExtensions(VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkPipelineShaderStageModuleIdentifierCreateInfoEXT moduleIdentifier = vku::InitStructHelper();
moduleIdentifier.identifierSize = 0;
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[0].pNext = &moduleIdentifier;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, IgnoredPipelineCreateFlags) {
TEST_DESCRIPTION("Create pipeline with invalid flags when allowed");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkPipelineCreateFlags2CreateInfo pipelineCreateFlags2 = vku::InitStructHelper();
pipelineCreateFlags2.flags = VK_PIPELINE_CREATE_2_DISABLE_OPTIMIZATION_BIT;
CreatePipelineHelper pipe(*this, &pipelineCreateFlags2);
pipe.gp_ci_.flags = 0x80000000;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, AttachmentCountIgnored) {
TEST_DESCRIPTION("https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/6535");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEquation);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorWriteMask);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendAdvanced);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT);
pipe.cb_ci_.attachmentCount = 0;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, NoRasterizationState) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7899");
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8051");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
AddRequiredFeature(vkt::Feature::extendedDynamicState2);
AddRequiredFeature(vkt::Feature::extendedDynamicState3DepthClampEnable);
AddRequiredFeature(vkt::Feature::extendedDynamicState3PolygonMode);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkPipelineMultisampleStateCreateInfo ms_ci = vku::InitStructHelper();
ms_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
ms_ci.sampleShadingEnable = 0;
ms_ci.minSampleShading = 1.0;
ms_ci.pSampleMask = nullptr;
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.pRasterizationState = nullptr;
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_POLYGON_MODE_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_CULL_MODE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_FRONT_FACE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS);
pipe.AddDynamicState(VK_DYNAMIC_STATE_LINE_WIDTH);
pipe.ms_ci_ = ms_ci;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, NoRasterizationStateDynamicRendering) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7899");
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8051");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
AddRequiredFeature(vkt::Feature::extendedDynamicState2);
AddRequiredFeature(vkt::Feature::extendedDynamicState3DepthClampEnable);
AddRequiredFeature(vkt::Feature::extendedDynamicState3PolygonMode);
RETURN_IF_SKIP(Init());
VkFormat color_formats = VK_FORMAT_UNDEFINED;
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_formats;
VkPipelineMultisampleStateCreateInfo ms_ci = vku::InitStructHelper();
ms_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
ms_ci.sampleShadingEnable = 0;
ms_ci.minSampleShading = 1.0;
ms_ci.pSampleMask = nullptr;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.gp_ci_.pRasterizationState = nullptr;
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_POLYGON_MODE_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_CULL_MODE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_FRONT_FACE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS);
pipe.AddDynamicState(VK_DYNAMIC_STATE_LINE_WIDTH);
pipe.ms_ci_ = ms_ci;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, ColorBlendUnsupportedLogicOpDynamic) {
TEST_DESCRIPTION("VkPipelineColorBlendStateCreateInfo::logicOpEnable is ignored with VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3LogicOpEnable);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT);
pipe.cb_ci_.logicOpEnable = VK_TRUE; // ignored now
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, PipelineMissingFeaturesDynamic) {
TEST_DESCRIPTION("Use dynamic state to set state that would be invalid since the features are not set");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
AddRequiredFeature(vkt::Feature::extendedDynamicState3AlphaToOneEnable);
AddRequiredFeature(vkt::Feature::extendedDynamicState3DepthClampEnable);
RETURN_IF_SKIP(Init());
const VkFormat ds_format = FindSupportedDepthStencilFormat(m_device->Physical());
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(ds_format, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL});
rp.AddDepthStencilAttachment(0);
rp.CreateRenderPass();
CreatePipelineHelper pipe(*this);
pipe.ds_ci_ = vku::InitStructHelper();
pipe.ds_ci_.depthBoundsTestEnable = VK_TRUE;
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE);
pipe.ms_ci_.alphaToOneEnable = VK_TRUE;
pipe.AddDynamicState(VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT);
pipe.rs_state_ci_.depthClampEnable = VK_TRUE;
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT);
pipe.gp_ci_.renderPass = rp;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, DepthClampControl) {
AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::depthClampControl);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDepthClampRangeEXT clamp_range = {0.0f, 1.0f};
VkPipelineViewportDepthClampControlCreateInfoEXT clamp_control = vku::InitStructHelper();
clamp_control.depthClampMode = VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT;
clamp_control.pDepthClampRange = &clamp_range;
CreatePipelineHelper pipe(*this);
pipe.vp_state_ci_.pNext = &clamp_control;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, DepthClampControlUnrestricted) {
AddRequiredExtensions(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::depthClampControl);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkDepthClampRangeEXT clamp_range = {-0.5f, 1.5f};
VkPipelineViewportDepthClampControlCreateInfoEXT clamp_control = vku::InitStructHelper();
clamp_control.depthClampMode = VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT;
clamp_control.pDepthClampRange = &clamp_range;
CreatePipelineHelper pipe(*this);
pipe.vp_state_ci_.pNext = &clamp_control;
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(PositivePipeline, DepthClampControlNullRange) {
AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::depthClampControl);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkPipelineViewportDepthClampControlCreateInfoEXT clamp_control = vku::InitStructHelper();
clamp_control.depthClampMode = VK_DEPTH_CLAMP_MODE_VIEWPORT_RANGE_EXT;
clamp_control.pDepthClampRange = nullptr;
CreatePipelineHelper pipe(*this);
pipe.vp_state_ci_.pNext = &clamp_control;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, GetPipelinePropertiesEXT) {
AddRequiredExtensions(VK_EXT_PIPELINE_PROPERTIES_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::pipelinePropertiesIdentifier);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.CreateGraphicsPipeline();
VkPipelineInfoEXT pipeline_info = vku::InitStructHelper();
pipeline_info.pipeline = pipe;
VkBaseOutStructure out_struct = {VK_STRUCTURE_TYPE_PIPELINE_PROPERTIES_IDENTIFIER_EXT, nullptr};
vk::GetPipelinePropertiesEXT(device(), &pipeline_info, &out_struct);
}
TEST_F(PositivePipeline, ColorWriteMaskE5B9G9R9) {
RETURN_IF_SKIP(Init());
if (!(m_device->FormatFeaturesOptimal(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) & VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT)) {
GTEST_SKIP() << "Device does not support VK_FORMAT_E5B9G9R9_UFLOAT_PACK32";
}
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL});
rp.AddColorAttachment(0);
rp.CreateRenderPass();
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.renderPass = rp;
pipe.cb_attachments_.colorWriteMask = VK_COLOR_COMPONENT_A_BIT;
{
pipe.CreateGraphicsPipeline();
pipe.Destroy();
}
pipe.cb_attachments_.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT;
{
pipe.CreateGraphicsPipeline();
pipe.Destroy();
}
pipe.cb_attachments_.colorWriteMask =
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
{
pipe.CreateGraphicsPipeline();
pipe.Destroy();
}
}
TEST_F(PositivePipeline, SampleLocations) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkMultisamplePropertiesEXT multisample_prop = vku::InitStructHelper();
vk::GetPhysicalDeviceMultisamplePropertiesEXT(Gpu(), VK_SAMPLE_COUNT_4_BIT, &multisample_prop);
if (multisample_prop.maxSampleLocationGridSize.width == 0 || multisample_prop.maxSampleLocationGridSize.height == 0) {
GTEST_SKIP() << "multisample properties are not supported";
}
VkImageCreateInfo image_ci = vku::InitStructHelper();
image_ci.imageType = VK_IMAGE_TYPE_2D;
image_ci.format = VK_FORMAT_R8G8B8A8_UNORM;
image_ci.extent = {32u, 32u, 1u};
image_ci.mipLevels = 1u;
image_ci.arrayLayers = 1u;
image_ci.samples = VK_SAMPLE_COUNT_4_BIT;
image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
image_ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
image_ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
vkt::Image ms_image(*m_device, image_ci);
vkt::ImageView ms_image_view = ms_image.CreateView();
image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
vkt::Image resolve_image(*m_device, image_ci);
vkt::ImageView resolve_image_view = resolve_image.CreateView();
VkClearValue clear_value = {m_clear_color};
RenderPassSingleSubpass render_pass(*this);
render_pass.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_4_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
render_pass.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
render_pass.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
render_pass.AddAttachmentReference({1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
render_pass.AddColorAttachment(0);
render_pass.AddResolveAttachment(1);
render_pass.CreateRenderPass();
VkImageView image_views[2] = {ms_image_view, resolve_image_view};
vkt::Framebuffer framebuffer(*m_device, render_pass, 2u, image_views);
std::vector<VkSampleLocationEXT> sample_location(4u, {0.5f, 0.5f});
VkSampleLocationsInfoEXT sample_locations_info = vku::InitStructHelper();
sample_locations_info.sampleLocationsPerPixel = VK_SAMPLE_COUNT_4_BIT;
sample_locations_info.sampleLocationGridSize = {1u, 1u};
sample_locations_info.sampleLocationsCount = 4u;
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_4_BIT;
multi_sample_state.sampleShadingEnable = VK_FALSE;
multi_sample_state.minSampleShading = 1.0f;
VkPipelineRenderingCreateInfo pipeline_rendering_ci = vku::InitStructHelper();
pipeline_rendering_ci.colorAttachmentCount = 1u;
pipeline_rendering_ci.pColorAttachmentFormats = &image_ci.format;
CreatePipelineHelper pipe(*this, &pipeline_rendering_ci);
pipe.gp_ci_.pMultisampleState = &multi_sample_state;
pipe.gp_ci_.renderPass = render_pass;
pipe.CreateGraphicsPipeline();
VkAttachmentSampleLocationsEXT initial_location;
initial_location.attachmentIndex = 0u;
initial_location.sampleLocationsInfo = sample_locations_info;
VkSubpassSampleLocationsEXT subpass_sample_locations;
subpass_sample_locations.subpassIndex = 0u;
subpass_sample_locations.sampleLocationsInfo = sample_locations_info;
m_command_buffer.Begin();
VkRenderPassSampleLocationsBeginInfoEXT sample_locations_begin_info = vku::InitStructHelper();
sample_locations_begin_info.attachmentInitialSampleLocationsCount = 1u;
sample_locations_begin_info.pAttachmentInitialSampleLocations = &initial_location;
sample_locations_begin_info.postSubpassSampleLocationsCount = 1u;
sample_locations_begin_info.pPostSubpassSampleLocations = &subpass_sample_locations;
VkRenderPassBeginInfo render_pass_begin_info = vku::InitStructHelper(&sample_locations_begin_info);
render_pass_begin_info.renderPass = render_pass;
render_pass_begin_info.framebuffer = framebuffer;
render_pass_begin_info.renderArea = {{0, 0}, {32u, 32u}};
render_pass_begin_info.clearValueCount = 1u;
render_pass_begin_info.pClearValues = &clear_value;
vk::CmdBeginRenderPass(m_command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
sample_locations_begin_info = {};
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u);
vk::CmdEndRenderPass(m_command_buffer);
m_command_buffer.End();
}
TEST_F(PositivePipeline, StaticConstantBlend) {
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkPipelineColorBlendAttachmentState cb_as;
cb_as.blendEnable = VK_TRUE;
cb_as.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
cb_as.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
cb_as.colorBlendOp = VK_BLEND_OP_ADD;
cb_as.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
cb_as.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
cb_as.alphaBlendOp = VK_BLEND_OP_ADD;
cb_as.colorWriteMask =
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
VkPipelineColorBlendStateCreateInfo cb_ci = vku::InitStructHelper();
cb_ci.attachmentCount = 1;
cb_ci.pAttachments = &cb_as;
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.pColorBlendState = &cb_ci;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(m_command_buffer, 3u, 1u, 0u, 0u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositivePipeline, BlendDisabled) {
AddRequiredFeature(vkt::Feature::independentBlend);
RETURN_IF_SKIP(Init());
VkFormat non_blend_format = VK_FORMAT_R8_SINT;
VkFormat blend_format = VK_FORMAT_R8G8B8A8_UNORM;
VkFormatFeatureFlags2 format_features1 = m_device->FormatFeaturesOptimal(non_blend_format);
VkFormatFeatureFlags2 format_features2 = m_device->FormatFeaturesOptimal(blend_format);
if (!(format_features1 & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) &&
(format_features1 & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)) {
GTEST_SKIP() << "Format features not suitable";
}
if (!(format_features2 & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) &&
!(format_features2 & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)) {
GTEST_SKIP() << "Format features not suitable";
}
vkt::Image non_blend_image(*m_device, 32u, 32u, non_blend_format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView non_blend_view = non_blend_image.CreateView();
vkt::Image blend_image(*m_device, 32u, 32u, blend_format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView blend_view = blend_image.CreateView();
VkAttachmentDescription attachments[2];
attachments[0] = {};
attachments[0].format = non_blend_format;
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].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[1] = {};
attachments[1].format = blend_format;
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference attachment_references1[2];
attachment_references1[0].attachment = 0u;
attachment_references1[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachment_references1[1].attachment = 1u;
attachment_references1[1].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference attachment_references2[2];
attachment_references2[0].attachment = VK_ATTACHMENT_UNUSED;
attachment_references2[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachment_references2[1].attachment = 1u;
attachment_references2[1].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpasses[2];
subpasses[0] = {};
subpasses[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpasses[0].colorAttachmentCount = 2u;
subpasses[0].pColorAttachments = attachment_references1;
subpasses[1] = {};
subpasses[1].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpasses[1].colorAttachmentCount = 2u;
subpasses[1].pColorAttachments = attachment_references2;
VkRenderPassCreateInfo render_pass_ci = vku::InitStructHelper();
render_pass_ci.attachmentCount = 2u;
render_pass_ci.pAttachments = attachments;
render_pass_ci.subpassCount = 2u;
render_pass_ci.pSubpasses = subpasses;
vkt::RenderPass render_pass(*m_device, render_pass_ci);
VkImageView views[2] = {non_blend_view, blend_view};
vkt::Framebuffer framebuffer(*m_device, render_pass, 2u, views);
VkPipelineColorBlendAttachmentState cb_attachments[2];
cb_attachments[0].blendEnable = VK_FALSE;
cb_attachments[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
cb_attachments[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
cb_attachments[0].colorBlendOp = VK_BLEND_OP_ADD;
cb_attachments[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
cb_attachments[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
cb_attachments[0].alphaBlendOp = VK_BLEND_OP_ADD;
cb_attachments[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT;
cb_attachments[1].blendEnable = VK_TRUE;
cb_attachments[1].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
cb_attachments[1].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
cb_attachments[1].colorBlendOp = VK_BLEND_OP_ADD;
cb_attachments[1].srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
cb_attachments[1].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
cb_attachments[1].alphaBlendOp = VK_BLEND_OP_ADD;
cb_attachments[1].colorWriteMask = VK_COLOR_COMPONENT_R_BIT;
VkPipelineColorBlendStateCreateInfo cb_state = vku::InitStructHelper();
cb_state.attachmentCount = 2u;
cb_state.pAttachments = cb_attachments;
CreatePipelineHelper pipe1(*this);
pipe1.gp_ci_.renderPass = render_pass;
pipe1.gp_ci_.pColorBlendState = &cb_state;
pipe1.CreateGraphicsPipeline();
cb_attachments[0].blendEnable = VK_TRUE;
CreatePipelineHelper pipe2(*this);
pipe2.gp_ci_.renderPass = render_pass;
pipe2.gp_ci_.subpass = 1u;
pipe2.gp_ci_.pColorBlendState = &cb_state;
pipe2.CreateGraphicsPipeline();
VkClearValue clear_values[2] = {{m_clear_color}, {m_clear_color}};
VkRenderPassBeginInfo render_pass_bi = vku::InitStructHelper();
render_pass_bi.renderPass = render_pass;
render_pass_bi.framebuffer = framebuffer;
render_pass_bi.renderArea = {{0, 0}, {32u, 32u}};
render_pass_bi.clearValueCount = 2u;
render_pass_bi.pClearValues = clear_values;
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(render_pass_bi);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe1);
vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u);
vk::CmdNextSubpass(m_command_buffer, VK_SUBPASS_CONTENTS_INLINE);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2);
vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositivePipeline, CustomResolve) {
AddRequiredExtensions(VK_EXT_CUSTOM_RESOLVE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::customResolve);
RETURN_IF_SKIP(Init());
VkFormat color_formats[2] = {VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM};
VkFormat ds_format = FindSupportedDepthStencilFormat(Gpu());
VkCustomResolveCreateInfoEXT custom_resolve_info = vku::InitStructHelper();
custom_resolve_info.customResolve = VK_TRUE;
custom_resolve_info.colorAttachmentCount = 1;
custom_resolve_info.pColorAttachmentFormats = &color_formats[0];
custom_resolve_info.depthAttachmentFormat = ds_format;
custom_resolve_info.stencilAttachmentFormat = VK_FORMAT_UNDEFINED;
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(&custom_resolve_info);
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_formats[1];
VkPipelineDepthStencilStateCreateInfo ds_ci = vku::InitStructHelper();
{
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.gp_ci_.pDepthStencilState = &ds_ci;
pipe.CreateGraphicsPipeline();
}
custom_resolve_info.depthAttachmentFormat = VK_FORMAT_UNDEFINED;
custom_resolve_info.stencilAttachmentFormat = ds_format;
{
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.gp_ci_.pDepthStencilState = &ds_ci;
pipe.CreateGraphicsPipeline();
}
}
TEST_F(PositivePipeline, NullDepthStencilState) {
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
RETURN_IF_SKIP(Init());
m_depth_stencil_fmt = FindSupportedDepthStencilFormat(Gpu());
m_depthStencil->Init(*m_device, m_width, m_height, 1, m_depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
vkt::ImageView depth_image_view = m_depthStencil->CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
InitRenderTarget(&depth_image_view.handle());
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_COMPARE_OP);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_STENCIL_OP);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdSetDepthTestEnableEXT(m_command_buffer, VK_FALSE);
vk::CmdSetStencilOpEXT(m_command_buffer, VK_STENCIL_FACE_FRONT_AND_BACK, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP,
VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS);
vk::CmdSetStencilTestEnableEXT(m_command_buffer, VK_TRUE);
vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositivePipeline, DisableShaderValidation) {
const VkLayerSettingEXT setting = {OBJECT_LAYER_NAME, "check_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkFalse};
VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 1, &setting};
RETURN_IF_SKIP(InitFramework(&layer_setting_ci));
RETURN_IF_SKIP(InitState());
const char *cs_source = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer SSBO {
uint x; // something to trigger pipeline validation
};
void main() {
x = 0;
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0);
pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr};
pipe.CreateComputePipeline();
vkt::Buffer buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
pipe.descriptor_set_.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
pipe.descriptor_set_.UpdateDescriptorSets();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_, 0, 1,
&pipe.descriptor_set_.set_, 0, nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
}
TEST_F(PositivePipeline, DisableShaderValidationMaintenance5) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance5);
const VkLayerSettingEXT setting = {OBJECT_LAYER_NAME, "check_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkFalse};
VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 1, &setting};
RETURN_IF_SKIP(InitFramework(&layer_setting_ci));
RETURN_IF_SKIP(InitState());
const char *cs_source = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer SSBO {
uint x; // something to trigger pipeline validation
};
void main() {
x = 0;
}
)glsl";
OneOffDescriptorSet ds(m_device, {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
});
vkt::PipelineLayout pipeline_layout(*m_device, {&ds.layout_});
vkt::Buffer buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
ds.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
ds.UpdateDescriptorSets();
std::vector<uint32_t> shader = GLSLToSPV(VK_SHADER_STAGE_COMPUTE_BIT, cs_source);
VkShaderModuleCreateInfo module_create_info = vku::InitStructHelper();
module_create_info.pCode = shader.data();
module_create_info.codeSize = shader.size() * sizeof(uint32_t);
VkPipelineShaderStageCreateInfo stage_ci = vku::InitStructHelper(&module_create_info);
stage_ci.stage = VK_SHADER_STAGE_COMPUTE_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
CreateComputePipelineHelper pipe(*this);
pipe.cp_ci_.stage = stage_ci;
pipe.cp_ci_.layout = pipeline_layout;
pipe.CreateComputePipeline(false);
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &ds.set_, 0, nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
}
TEST_F(PositivePipeline, DisableShaderValidationGPL) {
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary);
AddRequiredFeature(vkt::Feature::fragmentStoresAndAtomics);
const VkLayerSettingEXT setting = {OBJECT_LAYER_NAME, "check_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkFalse};
VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 1, &setting};
RETURN_IF_SKIP(InitFramework(&layer_setting_ci));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
const char *frag_shader = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer SSBO {
uint x; // something to trigger pipeline validation
};
void main() {
x = 0;
}
)glsl";
OneOffDescriptorSet ds(m_device, {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
vkt::PipelineLayout pipeline_layout(*m_device, {&ds.layout_});
vkt::Buffer buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
ds.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
ds.UpdateDescriptorSets();
vkt::SimpleGPL pipe(*this, pipeline_layout, kVertexMinimalGlsl, frag_shader);
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &ds.set_, 0, nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositivePipeline, DisableShaderValidationDraw) {
const VkLayerSettingEXT setting = {OBJECT_LAYER_NAME, "check_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkFalse};
VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 1, &setting};
RETURN_IF_SKIP(InitFramework(&layer_setting_ci));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(m_command_buffer, 3u, 1u, 0u, 0u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositivePipeline, DisableShaderValidationMesh) {
const VkLayerSettingEXT setting = {OBJECT_LAYER_NAME, "check_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkFalse};
VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 1, &setting};
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::meshShader);
RETURN_IF_SKIP(InitFramework(&layer_setting_ci));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
const char *mesh_source = R"glsl(
#version 460
#extension GL_EXT_mesh_shader : enable
layout(max_vertices = 3, max_primitives=1) out;
layout(triangles) out;
void main() {
SetMeshOutputsEXT(3,1);
}
)glsl";
VkShaderObj ms(*m_device, mesh_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2);
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_2);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {ms.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1,
&pipe.descriptor_set_->set_, 0, nullptr);
vk::CmdDrawMeshTasksEXT(m_command_buffer, 1, 1, 1);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositivePipeline, DisableShaderValidationGeomTess) {
const VkLayerSettingEXT setting = {OBJECT_LAYER_NAME, "check_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkFalse};
VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 1, &setting};
AddRequiredFeature(vkt::Feature::geometryShader);
AddRequiredFeature(vkt::Feature::tessellationShader);
RETURN_IF_SKIP(InitFramework(&layer_setting_ci));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
const char tess_src[] = R"glsl(
#version 460
layout(triangles, equal_spacing, cw, point_mode) in;
void main() { gl_Position = vec4(1); }
)glsl";
const char geom_src[] = R"glsl(
#version 450
layout (points) in;
layout (points) out;
layout (max_vertices = 1) out;
void main() {
gl_Position = vec4(1.0f, 0.5f, 0.5f, 0.0f);
gl_PointSize = 1.0f;
EmitVertex();
}
)glsl";
VkShaderObj tcs(*m_device, kTessellationControlMinimalGlsl, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
VkShaderObj tes(*m_device, tess_src, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
VkShaderObj gs(*m_device, geom_src, VK_SHADER_STAGE_GEOMETRY_BIT);
VkPipelineTessellationStateCreateInfo tess_ci = vku::InitStructHelper();
tess_ci.patchControlPoints = 4u;
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), tcs.GetStageCreateInfo(), tes.GetStageCreateInfo(),
gs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()};
pipe.ia_ci_.topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
pipe.tess_ci_ = tess_ci;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(m_command_buffer, 3u, 1u, 1u, 1u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositivePipeline, DepthBounds) {
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::depthBounds);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
RETURN_IF_SKIP(Init());
m_depth_stencil_fmt = FindSupportedDepthStencilFormat(Gpu());
m_depthStencil->Init(*m_device, m_width, m_height, 1, m_depth_stencil_fmt,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::ImageView depth_image_view = m_depthStencil->CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
InitRenderTarget(&depth_image_view.handle());
VkPipelineDepthStencilStateCreateInfo ds_ci = vku::InitStructHelper();
ds_ci.depthTestEnable = VK_FALSE;
ds_ci.minDepthBounds = 0.6f;
ds_ci.maxDepthBounds = 0.4f;
CreatePipelineHelper pipe(*this);
pipe.ds_ci_ = ds_ci;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositivePipeline, FramebufferMixedSamplesWithCoverageReductionTruncateNV) {
AddRequiredExtensions(VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME);
AddRequiredExtensions(VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::coverageReductionMode);
AddRequiredFeature(vkt::Feature::sampleRateShading);
RETURN_IF_SKIP(Init());
InitRenderTarget();
uint32_t combination_count = 0u;
vk::GetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(gpu_, &combination_count, nullptr);
std::vector<VkFramebufferMixedSamplesCombinationNV> combinations(combination_count);
for (auto &combination : combinations) {
combination = vku::InitStructHelper();
}
vk::GetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(gpu_, &combination_count, combinations.data());
VkCoverageReductionModeNV coverage_reduction_mode = VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV;
VkSampleCountFlagBits rasterization_samples = VK_SAMPLE_COUNT_4_BIT;
VkSampleCountFlagBits ds_samples = VK_SAMPLE_COUNT_4_BIT;
VkSampleCountFlagBits color_samples = VK_SAMPLE_COUNT_1_BIT;
bool found = false;
for (const auto &combination : combinations) {
if (combination.coverageReductionMode == coverage_reduction_mode &&
combination.rasterizationSamples == rasterization_samples &&
(combination.depthStencilSamples == VK_SAMPLE_COUNT_4_BIT) && (combination.colorSamples == VK_SAMPLE_COUNT_1_BIT)) {
found = true;
break;
}
}
if (!found) {
GTEST_SKIP() << "Required combination of mixed samples not supported";
}
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, color_samples, VK_IMAGE_LAYOUT_PREINITIALIZED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentDescription(VK_FORMAT_D24_UNORM_S8_UINT, ds_samples, VK_IMAGE_LAYOUT_PREINITIALIZED,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddAttachmentReference({1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL});
rp.AddColorAttachment(0);
rp.AddDepthStencilAttachment(1);
rp.CreateRenderPass();
VkPipelineDepthStencilStateCreateInfo ds = vku::InitStructHelper();
ds.depthTestEnable = VK_FALSE;
VkPipelineCoverageReductionStateCreateInfoNV cri = vku::InitStructHelper();
cri.coverageReductionMode = coverage_reduction_mode;
float cm_table = 0.0f;
VkPipelineCoverageModulationStateCreateInfoNV cmi = vku::InitStructHelper(&cri);
cmi.flags = 0;
cmi.coverageModulationTableEnable = false;
cmi.coverageModulationTableCount = 1;
cmi.pCoverageModulationTable = &cm_table;
const auto break_samples = [&cmi, &rp, &ds, &rasterization_samples](CreatePipelineHelper &helper) {
helper.ms_ci_.pNext = &cmi;
helper.ms_ci_.rasterizationSamples = rasterization_samples;
helper.ms_ci_.sampleShadingEnable = VK_TRUE;
helper.gp_ci_.renderPass = rp;
helper.gp_ci_.pDepthStencilState = &ds;
};
CreatePipelineHelper::OneshotTest(*this, break_samples, kErrorBit);
}