blob: 65339572379f08557731eeebda492b2f29662629 [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/render_pass_helper.h"
void DynamicStateTest::InitBasicExtendedDynamicState() {
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
RETURN_IF_SKIP(Init());
}
class PositiveDynamicState : public DynamicStateTest {};
TEST_F(PositiveDynamicState, DiscardRectanglesVersion) {
TEST_DESCRIPTION("check version of VK_EXT_discard_rectangles");
AddRequiredExtensions(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
if (!InstanceExtensionSupported(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME, 2)) {
GTEST_SKIP() << "need VK_EXT_discard_rectangles version 2";
}
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DISCARD_RECTANGLE_ENABLE_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdSetDiscardRectangleEnableEXT(m_command_buffer, VK_TRUE);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, ViewportWithCountNoMultiViewport) {
TEST_DESCRIPTION("DynamicViewportWithCount/ScissorWithCount without multiViewport feature not enabled.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT);
pipe.vp_state_ci_.viewportCount = 0;
pipe.vp_state_ci_.scissorCount = 0;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositiveDynamicState, CmdSetVertexInputEXT) {
TEST_DESCRIPTION("Test CmdSetVertexInputEXT");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::vertexInputDynamicState);
RETURN_IF_SKIP(Init());
InitRenderTarget();
// Fill with bad data as should be ignored with dynamic state
VkVertexInputBindingDescription input_binding = {5, 7, VK_VERTEX_INPUT_RATE_VERTEX};
VkVertexInputAttributeDescription input_attrib = {5, 7, VK_FORMAT_UNDEFINED, 9};
VkPipelineVertexInputStateCreateInfo vi_ci = vku::InitStructHelper();
vi_ci.pVertexBindingDescriptions = &input_binding;
vi_ci.vertexBindingDescriptionCount = 1;
vi_ci.pVertexAttributeDescriptions = &input_attrib;
vi_ci.vertexAttributeDescriptionCount = 1;
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
pipe.gp_ci_.pVertexInputState = &vi_ci; // ignored
pipe.CreateGraphicsPipeline();
VkVertexInputBindingDescription2EXT binding = vku::InitStructHelper();
binding.binding = 0;
binding.stride = sizeof(float);
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
binding.divisor = 1;
VkVertexInputAttributeDescription2EXT attribute = vku::InitStructHelper();
attribute.location = 0;
attribute.binding = 0;
attribute.format = VK_FORMAT_R32_SFLOAT;
attribute.offset = 0;
vkt::Buffer vtx_buf(*m_device, 1024, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
VkDeviceSize offset = 0;
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vtx_buf.handle(), &offset);
vk::CmdSetVertexInputEXT(m_command_buffer, 1, &binding, 1, &attribute);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, CmdSetVertexInputEXTStride) {
TEST_DESCRIPTION("Test CmdSetVertexInputEXT");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::vertexInputDynamicState);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE);
pipe.gp_ci_.pVertexInputState = nullptr;
pipe.CreateGraphicsPipeline();
VkVertexInputBindingDescription2EXT binding = vku::InitStructHelper();
binding.binding = 0;
binding.stride = sizeof(float);
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
binding.divisor = 1;
VkVertexInputAttributeDescription2EXT attribute = vku::InitStructHelper();
attribute.location = 0;
attribute.binding = 0;
attribute.format = VK_FORMAT_R32_SFLOAT;
attribute.offset = 0;
vkt::Buffer vtx_buf(*m_device, 1024, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
VkDeviceSize offset = 0;
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vtx_buf.handle(), &offset);
vk::CmdSetVertexInputEXT(m_command_buffer, 1, &binding, 1, &attribute);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, ExtendedDynamicStateBindVertexBuffersMaintenance5) {
TEST_DESCRIPTION("VK_KHR_maintenance5 lets you use VK_WHOLE_SIZE with VK_EXT_extended_dynamic_state");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance5);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
RETURN_IF_SKIP(Init());
m_command_buffer.Begin();
vkt::Buffer buffer(*m_device, 16, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
VkDeviceSize size = VK_WHOLE_SIZE;
VkDeviceSize offset = 0;
vk::CmdBindVertexBuffers2EXT(m_command_buffer, 0, 1, &buffer.handle(), &offset, &size, nullptr);
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DiscardRectanglesWithDynamicState) {
TEST_DESCRIPTION("Don't check discard rectangles if dynamic state is not set");
AddRequiredExtensions(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
InitRenderTarget();
// pass in struct, but don't set the dynamic state in the pipeline
VkPipelineDiscardRectangleStateCreateInfoEXT discard_rect_ci = vku::InitStructHelper();
discard_rect_ci.discardRectangleMode = VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT;
discard_rect_ci.discardRectangleCount = 4;
std::vector<VkRect2D> discard_rectangles(4);
discard_rect_ci.pDiscardRectangles = discard_rectangles.data();
CreatePipelineHelper pipe(*this, &discard_rect_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, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DynamicColorWriteNoColorAttachments) {
TEST_DESCRIPTION("Create a graphics pipeline with no color attachments, but use dynamic color write enable.");
AddRequiredExtensions(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::colorWriteEnable);
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);
// Create a render pass without any color attachments
VkAttachmentReference attach = {};
attach.attachment = 0;
attach.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpasses = {};
subpasses.pDepthStencilAttachment = &attach;
VkAttachmentDescription attach_desc = {};
attach_desc.format = m_depth_stencil_fmt;
attach_desc.samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attach_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attach_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attach_desc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attach_desc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
VkRenderPassCreateInfo rpci = vku::InitStructHelper();
rpci.attachmentCount = 1;
rpci.pAttachments = &attach_desc;
rpci.subpassCount = 1;
rpci.pSubpasses = &subpasses;
vkt::RenderPass rp(*m_device, rpci);
vkt::Framebuffer fb(*m_device, rp, 1, &depth_image_view.handle(), m_width, m_height);
// Enable dynamic color write enable
pipe.gp_ci_.renderPass = rp;
// pColorBlendState is not required since there are no color attachments
pipe.gp_ci_.pColorBlendState = nullptr;
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT);
pipe.ds_ci_ = vku::InitStructHelper();
pipe.ds_ci_.depthTestEnable = VK_TRUE;
pipe.ds_ci_.stencilTestEnable = VK_TRUE;
ASSERT_EQ(VK_SUCCESS, pipe.CreateGraphicsPipeline());
m_command_buffer.Begin();
m_renderPassBeginInfo.renderPass = rp;
m_renderPassBeginInfo.framebuffer = fb;
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
VkBool32 color_write_enable = VK_TRUE;
vk::CmdSetColorWriteEnableEXT(m_command_buffer, 1, &color_write_enable);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1,
&pipe.descriptor_set_->set_, 0, nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DepthTestEnableOverridesPipelineDepthWriteEnable) {
RETURN_IF_SKIP(InitBasicExtendedDynamicState());
vkt::Image color_image(*m_device, m_width, m_height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
auto color_view = color_image.CreateView();
VkFormat ds_format = FindSupportedDepthStencilFormat(Gpu());
vkt::Image ds_image(*m_device, m_width, m_height, ds_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
auto ds_view = ds_image.CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM);
rp.AddAttachmentDescription(ds_format, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL});
rp.AddAttachmentReference({1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL});
rp.AddColorAttachment(0);
rp.AddDepthStencilAttachment(1);
rp.CreateRenderPass();
VkImageView views[2] = {color_view, ds_view};
vkt::Framebuffer fb(*m_device, rp, 2, views);
VkPipelineDepthStencilStateCreateInfo ds_state = vku::InitStructHelper();
ds_state.depthWriteEnable = VK_TRUE;
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE);
pipe.gp_ci_.renderPass = rp;
pipe.ds_ci_ = ds_state;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_command_buffer.BeginRenderPass(rp, fb);
vk::CmdSetDepthTestEnableEXT(m_command_buffer, VK_FALSE);
vk::CmdDraw(m_command_buffer, 1, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DepthTestEnableOverridesDynamicDepthWriteEnable) {
TEST_DESCRIPTION("setting vkCmdSetDepthTestEnable to false cancels what ever is written to vkCmdSetDepthWriteEnable.");
RETURN_IF_SKIP(InitBasicExtendedDynamicState());
vkt::Image color_image(*m_device, m_width, m_height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
auto color_view = color_image.CreateView();
VkFormat ds_format = FindSupportedDepthStencilFormat(Gpu());
vkt::Image ds_image(*m_device, m_width, m_height, ds_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
auto ds_view = ds_image.CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM);
rp.AddAttachmentDescription(ds_format, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL});
rp.AddAttachmentReference({1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL});
rp.AddColorAttachment(0);
rp.AddDepthStencilAttachment(1);
rp.CreateRenderPass();
VkImageView views[2] = {color_view, ds_view};
vkt::Framebuffer fb(*m_device, rp, 2, views);
VkPipelineDepthStencilStateCreateInfo ds_state = vku::InitStructHelper();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE);
pipe.gp_ci_.renderPass = rp;
pipe.ds_ci_ = ds_state;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_command_buffer.BeginRenderPass(rp, fb);
vk::CmdSetDepthTestEnableEXT(m_command_buffer, VK_FALSE);
vk::CmdSetDepthWriteEnableEXT(m_command_buffer, VK_TRUE);
vk::CmdDraw(m_command_buffer, 1, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DepthTestEnableDepthWriteEnable) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-Docs/issues/2522");
RETURN_IF_SKIP(InitBasicExtendedDynamicState());
vkt::Image color_image(*m_device, m_width, m_height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
auto color_view = color_image.CreateView();
VkFormat ds_format = FindSupportedDepthStencilFormat(Gpu());
vkt::Image ds_image(*m_device, m_width, m_height, ds_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
auto ds_view = ds_image.CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM);
rp.AddAttachmentDescription(ds_format, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL});
rp.AddAttachmentReference({1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL});
rp.AddColorAttachment(0);
rp.AddDepthStencilAttachment(1);
rp.CreateRenderPass();
VkImageView views[2] = {color_view, ds_view};
vkt::Framebuffer fb(*m_device, rp, 2, views);
VkPipelineDepthStencilStateCreateInfo ds_state = vku::InitStructHelper();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE);
pipe.gp_ci_.renderPass = rp;
pipe.ds_ci_ = ds_state;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_command_buffer.BeginRenderPass(rp, fb);
vk::CmdSetDepthTestEnableEXT(m_command_buffer, VK_FALSE);
// never call vkCmdSetDepthWriteEnableEXT as not needed
vk::CmdDraw(m_command_buffer, 1, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, SetBeforePipeline) {
TEST_DESCRIPTION("Pipeline set state, but prior to last bound pipeline that had it");
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe_line(*this);
pipe_line.AddDynamicState(VK_DYNAMIC_STATE_LINE_WIDTH);
pipe_line.CreateGraphicsPipeline();
CreatePipelineHelper pipe_blend(*this);
pipe_blend.AddDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
pipe_blend.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdSetLineWidth(m_command_buffer, 1.0f);
float blends[4] = {1.0f, 1.0f, 1.0f, 1.0f};
vk::CmdSetBlendConstants(m_command_buffer, blends);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_line);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_blend);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, AttachmentFeedbackLoopEnable) {
TEST_DESCRIPTION("Use vkCmdSetAttachmentFeedbackLoopEnableEXT correctly");
AddRequiredExtensions(VK_EXT_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::attachmentFeedbackLoopDynamicState);
AddRequiredFeature(vkt::Feature::attachmentFeedbackLoopLayout);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_ATTACHMENT_FEEDBACK_LOOP_ENABLE_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
vk::CmdSetAttachmentFeedbackLoopEnableEXT(m_command_buffer, VK_IMAGE_ASPECT_COLOR_BIT);
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();
}
TEST_F(PositiveDynamicState, SetDepthBias2EXTDepthBiasClampEnabled) {
TEST_DESCRIPTION("Call vkCmdSetDepthBias2EXT with VkPhysicalDeviceFeatures::depthBiasClamp feature enabled");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState2);
AddRequiredFeature(vkt::Feature::depthBiasControl);
AddRequiredFeature(vkt::Feature::depthBiasClamp);
RETURN_IF_SKIP(Init());
InitRenderTarget();
// Create a pipeline with a dynamically set depth bias
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS);
VkPipelineRasterizationStateCreateInfo raster_state = vku::InitStructHelper();
raster_state.depthBiasEnable = VK_TRUE;
raster_state.lineWidth = 1.0f;
pipe.rs_state_ci_ = raster_state;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
vk::CmdSetDepthBiasEnableEXT(m_command_buffer, VK_TRUE);
VkDepthBiasInfoEXT depth_bias_info = vku::InitStructHelper();
depth_bias_info.depthBiasConstantFactor = 1.0f;
depth_bias_info.depthBiasClamp = 1.0f;
depth_bias_info.depthBiasSlopeFactor = 1.0f;
vk::CmdSetDepthBias2EXT(m_command_buffer, &depth_bias_info);
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); // Without correct state tracking, VUID-vkCmdDraw-None-07834 would be thrown here
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, SetDepthBias2EXTDepthBiasClampDisabled) {
TEST_DESCRIPTION("Call vkCmdSetDepthBias2EXT with VkPhysicalDeviceFeatures::depthBiasClamp feature disabled");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState2);
RETURN_IF_SKIP(Init());
InitRenderTarget();
// Create a pipeline with a dynamically set depth bias
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS);
VkPipelineRasterizationStateCreateInfo raster_state = vku::InitStructHelper();
raster_state.depthBiasEnable = VK_TRUE;
raster_state.lineWidth = 1.0f;
pipe.rs_state_ci_ = raster_state;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
vk::CmdSetDepthBiasEnableEXT(m_command_buffer, VK_TRUE);
VkDepthBiasInfoEXT depth_bias_info = vku::InitStructHelper();
depth_bias_info.depthBiasConstantFactor = 1.0f;
depth_bias_info.depthBiasClamp = 0.0f; // depthBiasClamp feature is disabled, so depth_bias_info.depthBiasClamp must be 0
depth_bias_info.depthBiasSlopeFactor = 1.0f;
vk::CmdSetDepthBias2EXT(m_command_buffer, &depth_bias_info);
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); // Without correct state tracking, VUID-vkCmdDraw-None-07834 would be thrown here
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, SetDepthBias2EXTDepthBiasWithDepthBiasRepresentationInfo) {
TEST_DESCRIPTION(
"Call vkCmdSetDepthBias2EXT with VkDepthBiasRepresentationInfoEXT and VkPhysicalDeviceFeatures::depthBiasClamp and "
"VkPhysicalDeviceDepthBiasControlFeaturesEXT "
"features enabled");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState2);
AddRequiredFeature(vkt::Feature::leastRepresentableValueForceUnormRepresentation);
AddRequiredFeature(vkt::Feature::floatRepresentation);
AddRequiredFeature(vkt::Feature::depthBiasExact);
AddRequiredFeature(vkt::Feature::depthBiasClamp);
RETURN_IF_SKIP(Init());
InitRenderTarget();
// Create a pipeline with a dynamically set depth bias
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS);
VkPipelineRasterizationStateCreateInfo raster_state = vku::InitStructHelper();
raster_state.depthBiasEnable = VK_TRUE;
raster_state.lineWidth = 1.0f;
pipe.rs_state_ci_ = raster_state;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
vk::CmdSetDepthBiasEnableEXT(m_command_buffer, VK_TRUE);
VkDepthBiasInfoEXT depth_bias_info = vku::InitStructHelper();
depth_bias_info.depthBiasConstantFactor = 1.0f;
depth_bias_info.depthBiasClamp = 1.0f;
depth_bias_info.depthBiasSlopeFactor = 1.0f;
vk::CmdSetDepthBias2EXT(m_command_buffer, &depth_bias_info);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
// Without correct state tracking, VUID-vkCmdDraw-None-07834 would be thrown here and in the follow-up calls
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
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;
depth_bias_info.pNext = &depth_bias_representation;
vk::CmdSetDepthBias2EXT(m_command_buffer, &depth_bias_info);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
depth_bias_representation.depthBiasRepresentation = VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT;
vk::CmdSetDepthBias2EXT(m_command_buffer, &depth_bias_info);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, AlphaToCoverageSetFalse) {
TEST_DESCRIPTION("Dynamically set alphaToCoverageEnabled to false so its not checked.");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3AlphaToCoverageEnable);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *fsSource = R"glsl(
#version 450
layout(location = 0) out float x;
void main(){
x = 1.0;
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineMultisampleStateCreateInfo ms_state_ci = vku::InitStructHelper();
ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
ms_state_ci.alphaToCoverageEnable = VK_TRUE; // should be ignored
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.AddDynamicState(VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT);
pipe.ms_ci_ = ms_state_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::CmdSetAlphaToCoverageEnableEXT(m_command_buffer, VK_FALSE);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, AlphaToCoverageSetTrue) {
TEST_DESCRIPTION("Dynamically set alphaToCoverageEnabled to true, but have component set.");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3AlphaToCoverageEnable);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdSetAlphaToCoverageEnableEXT(m_command_buffer, VK_TRUE);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, MultisampleStateIgnored) {
TEST_DESCRIPTION("Ignore null pMultisampleState, with alphaToOne disabled");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3RasterizationSamples);
AddRequiredFeature(vkt::Feature::extendedDynamicState3SampleMask);
AddRequiredFeature(vkt::Feature::extendedDynamicState3AlphaToCoverageEnable);
AddRequiredFeature(vkt::Feature::extendedDynamicState3AlphaToOneEnable);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_SAMPLE_MASK_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT);
pipe.gp_ci_.pMultisampleState = nullptr;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositiveDynamicState, MultisampleStateIgnoredAlphaToOne) {
TEST_DESCRIPTION("Ignore null pMultisampleState with alphaToOne enabled");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3RasterizationSamples);
AddRequiredFeature(vkt::Feature::extendedDynamicState3SampleMask);
AddRequiredFeature(vkt::Feature::extendedDynamicState3AlphaToCoverageEnable);
AddRequiredFeature(vkt::Feature::extendedDynamicState3AlphaToOneEnable);
AddRequiredFeature(vkt::Feature::alphaToOne);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_SAMPLE_MASK_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT);
pipe.gp_ci_.pMultisampleState = nullptr;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositiveDynamicState, InputAssemblyStateIgnored) {
TEST_DESCRIPTION("Ignore null pInputAssemblyState");
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();
VkPhysicalDeviceExtendedDynamicState3PropertiesEXT dynamic_state_3_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(dynamic_state_3_props);
if (!dynamic_state_3_props.dynamicPrimitiveTopologyUnrestricted) {
GTEST_SKIP() << "dynamicPrimitiveTopologyUnrestricted is VK_FALSE";
}
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY);
pipe.gp_ci_.pInputAssemblyState = nullptr;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositiveDynamicState, ViewportStateIgnored) {
TEST_DESCRIPTION("Ignore null pViewportState");
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());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.rs_state_ci_.rasterizerDiscardEnable = VK_FALSE;
pipe.gp_ci_.pViewportState = nullptr;
pipe.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT);
pipe.CreateGraphicsPipeline();
}
TEST_F(PositiveDynamicState, ColorBlendStateIgnored) {
TEST_DESCRIPTION("Ignore null pColorBlendState");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState2);
AddRequiredFeature(vkt::Feature::extendedDynamicState2LogicOp);
AddRequiredFeature(vkt::Feature::extendedDynamicState3LogicOpEnable);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEquation);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorWriteMask);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_LOGIC_OP_EXT);
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_BLEND_CONSTANTS);
VkPipelineColorBlendAttachmentState att_state = {};
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR;
att_state.blendEnable = VK_TRUE;
pipe.cb_attachments_ = att_state;
pipe.gp_ci_.pColorBlendState = nullptr;
pipe.CreateGraphicsPipeline();
}
TEST_F(PositiveDynamicState, DepthBoundsTestEnableState) {
TEST_DESCRIPTION("Dynamically set depthBoundsTestEnable and not call vkCmdSetDepthBounds before the draw");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState);
RETURN_IF_SKIP(Init());
// Need to set format framework uses for InitRenderTarget
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());
CreatePipelineHelper pipe(*this);
pipe.ds_ci_ = vku::InitStructHelper();
pipe.ds_ci_.depthTestEnable = VK_TRUE; // ignored
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdSetDepthBoundsTestEnableEXT(m_command_buffer, VK_FALSE);
// don't need vkCmdSetDepthBounds since test is disabled now
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, ViewportInheritance) {
TEST_DESCRIPTION("Dynamically set viewport multiple times");
AddRequiredExtensions(VK_NV_INHERITED_VIEWPORT_SCISSOR_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::multiViewport);
AddRequiredFeature(vkt::Feature::inheritedViewportScissor2D);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.vp_state_ci_.viewportCount = 2u;
pipe.vp_state_ci_.scissorCount = 2u;
pipe.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR);
pipe.CreateGraphicsPipeline();
vkt::CommandBuffer cmd_buffer(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
vkt::CommandBuffer set_state(*m_device, m_command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
const VkViewport viewports[2] = {{0.0f, 0.0f, 100.0f, 100.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 100.0f, 100.0f, 0.0f, 1.0f}};
const VkRect2D scissors[2] = {{{0, 0}, {100u, 100u}}, {{0, 0}, {100u, 100u}}};
auto viewport_scissor_inheritance = vku::InitStruct<VkCommandBufferInheritanceViewportScissorInfoNV>();
viewport_scissor_inheritance.viewportScissor2D = VK_TRUE;
viewport_scissor_inheritance.viewportDepthCount = 2u;
viewport_scissor_inheritance.pViewportDepths = viewports;
auto hinfo = vku::InitStruct<VkCommandBufferInheritanceInfo>(&viewport_scissor_inheritance);
hinfo.renderPass = m_renderPass;
hinfo.subpass = 0;
hinfo.framebuffer = Framebuffer();
auto info = vku::InitStruct<VkCommandBufferBeginInfo>();
info.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
info.pInheritanceInfo = &hinfo;
cmd_buffer.Begin(&info);
vk::CmdBindPipeline(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(cmd_buffer, 3, 1, 0, 0);
cmd_buffer.End();
set_state.Begin();
vk::CmdSetViewport(set_state, 1u, 1u, &viewports[1]);
set_state.End();
m_command_buffer.Begin();
vk::CmdSetViewport(m_command_buffer, 0u, 2u, viewports);
vk::CmdSetViewport(m_command_buffer, 0u, 1u, viewports);
vk::CmdSetScissor(m_command_buffer, 0u, 2u, scissors);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
vk::CmdExecuteCommands(m_command_buffer, 1u, &cmd_buffer.handle());
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
}
TEST_F(PositiveDynamicState, AttachmentFeedbackLoopEnableAspectMask) {
TEST_DESCRIPTION("Valid aspect masks for vkCmdSetAttachmentFeedbackLoopEnableEXT");
AddRequiredExtensions(VK_EXT_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::attachmentFeedbackLoopDynamicState);
AddRequiredFeature(vkt::Feature::attachmentFeedbackLoopLayout);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_ATTACHMENT_FEEDBACK_LOOP_ENABLE_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
vk::CmdSetAttachmentFeedbackLoopEnableEXT(m_command_buffer, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, RasterizationSamplesDynamicRendering) {
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3RasterizationSamples);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM;
VkImageCreateInfo image_ci = vku::InitStructHelper();
image_ci.imageType = VK_IMAGE_TYPE_2D;
image_ci.format = color_format;
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;
vkt::Image image(*m_device, image_ci, vkt::set_layout);
vkt::ImageView image_view = image.CreateView();
vkt::Image resolve_image(*m_device, 32u, 32u, color_format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView resolve_image_view = resolve_image.CreateView();
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_format;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT);
pipe.CreateGraphicsPipeline();
VkRenderingAttachmentInfo colorAttachment = vku::InitStructHelper();
colorAttachment.imageView = image_view;
colorAttachment.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
colorAttachment.resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT;
colorAttachment.resolveImageView = resolve_image_view;
colorAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_GENERAL;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.clearValue.color = m_clear_color;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea = {{0, 0}, {32u, 32u}};
rendering_info.layerCount = 1u;
rendering_info.colorAttachmentCount = 1u;
rendering_info.pColorAttachments = &colorAttachment;
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
vk::CmdSetRasterizationSamplesEXT(m_command_buffer, VK_SAMPLE_COUNT_4_BIT);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u);
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, RasterizationSamples) {
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3RasterizationSamples);
RETURN_IF_SKIP(Init());
VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM;
VkImageCreateInfo image_ci = vku::InitStructHelper();
image_ci.imageType = VK_IMAGE_TYPE_2D;
image_ci.format = color_format;
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;
vkt::Image image(*m_device, image_ci, vkt::set_layout);
vkt::ImageView image_view = image.CreateView();
vkt::Image resolve_image(*m_device, 32u, 32u, color_format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView resolve_image_view = resolve_image.CreateView();
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(color_format, VK_SAMPLE_COUNT_4_BIT);
rp.AddAttachmentDescription(color_format, VK_SAMPLE_COUNT_1_BIT);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddAttachmentReference({1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddColorAttachment(0);
rp.AddResolveAttachment(1);
rp.CreateRenderPass();
VkImageView attachments[2] = {image_view, resolve_image_view};
const vkt::Framebuffer fb(*m_device, rp, 2, attachments);
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT);
pipe.gp_ci_.renderPass = rp;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(rp, fb, 32u, 32u);
vk::CmdSetRasterizationSamplesEXT(m_command_buffer, VK_SAMPLE_COUNT_4_BIT);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, PrimitiveTopology) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8028");
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_PRIMITIVE_RESTART_ENABLE);
pipe.AddDynamicState(VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY);
pipe.ia_ci_.primitiveRestartEnable = VK_FALSE;
pipe.ia_ci_.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdSetPrimitiveTopologyEXT(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
vk::CmdSetPrimitiveRestartEnableEXT(m_command_buffer, VK_TRUE);
vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, VertexInputMultipleBindings) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8458");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::vertexInputDynamicState);
RETURN_IF_SKIP(Init());
InitRenderTarget();
struct PerVertex {
int a;
float b;
};
struct PerInstance {
uint32_t c;
float d;
};
VkVertexInputBindingDescription2EXT bindings[2];
bindings[0] = vku::InitStructHelper();
bindings[0].binding = 0u;
bindings[0].stride = sizeof(PerVertex);
bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
bindings[0].divisor = 1u;
bindings[1] = vku::InitStructHelper();
bindings[1].binding = 1u;
bindings[1].stride = 0u;
bindings[1].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
bindings[1].divisor = 1u;
VkVertexInputAttributeDescription2EXT attributes[4];
attributes[0] = vku::InitStructHelper();
attributes[0].location = 0u;
attributes[0].binding = 0u;
attributes[0].format = VK_FORMAT_R8_SINT;
attributes[0].offset = offsetof(PerVertex, a);
attributes[1] = vku::InitStructHelper();
attributes[1].location = 1u;
attributes[1].binding = 0u;
attributes[1].format = VK_FORMAT_R32_SFLOAT;
attributes[1].offset = offsetof(PerVertex, b);
attributes[2] = vku::InitStructHelper();
attributes[2].location = 2u;
attributes[2].binding = 1u;
attributes[2].format = VK_FORMAT_R8_UINT;
attributes[2].offset = offsetof(PerInstance, c);
attributes[3] = vku::InitStructHelper();
attributes[3].location = 3u;
attributes[3].binding = 1u;
attributes[3].format = VK_FORMAT_R32_SFLOAT;
attributes[3].offset = offsetof(PerInstance, d);
const char *vsSource = R"glsl(
#version 450
layout(location = 0) in int a;
layout(location = 1) in float b;
layout(location = 2) in uint c;
layout(location = 3) in float d;
void main(){
gl_Position = vec4(float(a), b, float(c), d);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
vkt::Buffer vertex_buffer(*m_device, 1024, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
vkt::Buffer instance_buffer(*m_device, 1024, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
VkBuffer buffers[2] = {vertex_buffer, instance_buffer};
VkDeviceSize offsets[2] = {0u, 0u};
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindVertexBuffers(m_command_buffer, 0, 2, buffers, offsets);
vk::CmdSetVertexInputEXT(m_command_buffer, 2, bindings, 4, attributes);
vk::CmdDraw(m_command_buffer, 3u, 3u, 0u, 0u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, ColorBlendEquationMultipleAttachments) {
TEST_DESCRIPTION("Only update some of the dynamic color blend equations");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEquation);
RETURN_IF_SKIP(Init());
InitRenderTarget(2);
VkPipelineColorBlendAttachmentState color_blend[2] = {};
color_blend[0] = DefaultColorBlendAttachmentState();
color_blend[1] = DefaultColorBlendAttachmentState();
CreatePipelineHelper pipe(*this);
pipe.cb_ci_.attachmentCount = 2;
pipe.cb_ci_.pAttachments = color_blend;
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
const VkColorBlendEquationEXT equation = {VK_BLEND_FACTOR_SRC_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_OP_ADD,
VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD};
vk::CmdSetColorBlendEquationEXT(m_command_buffer, 0, 1, &equation);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdSetColorBlendEquationEXT(m_command_buffer, 1, 1, &equation);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, MaxFragmentDualSrcAttachmentsDynamicBlendEnable) {
TEST_DESCRIPTION("Test maxFragmentDualSrcAttachments when blend is not enabled.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dualSrcBlend);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEquation);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorWriteMask);
RETURN_IF_SKIP(Init());
const uint32_t count = m_device->Physical().limits_.maxFragmentDualSrcAttachments + 1;
if (count != 2) {
GTEST_SKIP() << "Test is designed for a maxFragmentDualSrcAttachments of 1";
}
InitRenderTarget(count);
const char *fs_src = R"glsl(
#version 460
layout(location = 0) out vec4 c0;
layout(location = 1) out vec4 c1;
void main() {
c0 = vec4(0.0f);
c1 = vec4(0.0f);
}
)glsl";
VkShaderObj fs(*m_device, fs_src, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineColorBlendAttachmentState cb_attachments = DefaultColorBlendAttachmentState();
CreatePipelineHelper pipe(*this);
pipe.cb_ci_.pAttachments = &cb_attachments;
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
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.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
VkColorBlendEquationEXT dual_color_blend_equation = {
VK_BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_OP_ADD,
VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD};
VkColorBlendEquationEXT normal_color_blend_equation = {
VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_OP_ADD,
VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD};
vk::CmdSetColorBlendEquationEXT(m_command_buffer, 0, 1, &dual_color_blend_equation);
vk::CmdSetColorBlendEquationEXT(m_command_buffer, 1, 1, &normal_color_blend_equation);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
// The dual color blend is disabled
VkBool32 color_blend_enabled[2] = {VK_FALSE, VK_TRUE};
vk::CmdSetColorBlendEnableEXT(m_command_buffer, 0, 2, color_blend_enabled);
VkColorComponentFlags color_component_flags[2] = {VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_R_BIT};
vk::CmdSetColorWriteMaskEXT(m_command_buffer, 0, 2, color_component_flags);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DynamicColorBlendEnable) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8444");
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable);
RETURN_IF_SKIP(Init());
InitDynamicRenderTarget();
const VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM;
const VkFormat depth_stencil_format = FindSupportedDepthStencilFormat(Gpu());
VkImageCreateInfo image_ci = vku::InitStructHelper();
image_ci.imageType = VK_IMAGE_TYPE_2D;
image_ci.format = color_format;
image_ci.extent = {32u, 32u, 1u};
image_ci.mipLevels = 1u;
image_ci.arrayLayers = 1u;
image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
image_ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
vkt::Image image1(*m_device, image_ci, vkt::set_layout);
vkt::Image image2(*m_device, image_ci, vkt::set_layout);
vkt::Image image3(*m_device, image_ci, vkt::set_layout);
vkt::ImageView image_view1 = image1.CreateView();
vkt::ImageView image_view2 = image2.CreateView();
vkt::ImageView image_view3 = image3.CreateView();
vkt::Image depth_image(*m_device, 32, 32, depth_stencil_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
vkt::ImageView depth_image_view = depth_image.CreateView(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
VkRenderingAttachmentInfo color_attachments[3];
color_attachments[0] = vku::InitStructHelper();
color_attachments[0].imageView = image_view1;
color_attachments[0].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachments[1] = color_attachments[0];
color_attachments[1].imageView = image_view2;
color_attachments[2] = color_attachments[0];
color_attachments[2].imageView = image_view3;
VkRenderingAttachmentInfo depth_attachment = vku::InitStructHelper();
depth_attachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depth_attachment.imageView = depth_image_view;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea = {{0, 0}, {32u, 32u}};
rendering_info.layerCount = 1u;
rendering_info.colorAttachmentCount = 3u;
rendering_info.pColorAttachments = color_attachments;
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_format;
pipeline_rendering_info.depthAttachmentFormat = depth_stencil_format;
pipeline_rendering_info.stencilAttachmentFormat = depth_stencil_format;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
vk::CmdBeginRenderingKHR(m_command_buffer, &rendering_info);
VkBool32 color_blend_enables[] = {VK_TRUE, VK_TRUE, VK_TRUE};
vk::CmdSetColorBlendEnableEXT(m_command_buffer, 0u, 3u, color_blend_enables);
vk::CmdEndRenderingKHR(m_command_buffer);
rendering_info.colorAttachmentCount = 1u;
rendering_info.pDepthAttachment = &depth_attachment;
vk::CmdBeginRenderingKHR(m_command_buffer, &rendering_info);
VkBool32 color_blend_disabled = VK_FALSE;
vk::CmdSetColorBlendEnableEXT(m_command_buffer, 0u, 1u, &color_blend_disabled);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdDraw(m_command_buffer, 3u, 1u, 0u, 0u);
vk::CmdEndRenderingKHR(m_command_buffer);
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DynamicAdvancedBlendMaxAttachments) {
TEST_DESCRIPTION("Attempt to use the maximum attachments in subpass when advanced blend is enabled");
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendAdvanced);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT blend_advanced_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(blend_advanced_props);
const uint32_t attachment_count = blend_advanced_props.advancedBlendMaxColorAttachments;
VkImageCreateInfo image_ci = vku::InitStructHelper();
image_ci.imageType = VK_IMAGE_TYPE_2D;
image_ci.format = VK_FORMAT_R8G8B8A8_UNORM;
image_ci.extent = {32, 32, 1};
image_ci.mipLevels = 1u;
image_ci.arrayLayers = 1u;
image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
image_ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
image_ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
std::vector<std::unique_ptr<vkt::Image>> images(attachment_count);
std::vector<vkt::ImageView> image_views(attachment_count);
std::vector<VkRenderingAttachmentInfo> rendering_attachment_info(attachment_count);
std::vector<VkFormat> formats(attachment_count);
std::vector<VkPipelineColorBlendAttachmentState> color_blend_attachments(attachment_count);
for (uint32_t i = 0; i < attachment_count; ++i) {
images[i] = std::make_unique<vkt::Image>(*m_device, image_ci);
image_views[i] = images[i]->CreateView();
rendering_attachment_info[i] = vku::InitStructHelper();
rendering_attachment_info[i].imageView = image_views[i];
rendering_attachment_info[i].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
rendering_attachment_info[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
rendering_attachment_info[i].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
rendering_attachment_info[i].clearValue.color = m_clear_color;
formats[i] = image_ci.format;
color_blend_attachments[i] = DefaultColorBlendAttachmentState();
}
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = attachment_count;
pipeline_rendering_info.pColorAttachmentFormats = formats.data();
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT);
pipe.cb_ci_.attachmentCount = attachment_count;
pipe.cb_ci_.pAttachments = color_blend_attachments.data();
pipe.CreateGraphicsPipeline();
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea = {{0, 0}, {32, 32}};
rendering_info.layerCount = 1u;
rendering_info.colorAttachmentCount = attachment_count;
rendering_info.pColorAttachments = rendering_attachment_info.data();
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
for (uint32_t i = 0; i < attachment_count; ++i) {
VkBool32 color_blend_enable = i == 0;
vk::CmdSetColorBlendEnableEXT(m_command_buffer, i, 1u, &color_blend_enable);
VkColorBlendAdvancedEXT color_blend_advanced;
color_blend_advanced.advancedBlendOp = VK_BLEND_OP_ADD;
color_blend_advanced.srcPremultiplied = VK_FALSE;
color_blend_advanced.dstPremultiplied = VK_FALSE;
color_blend_advanced.blendOverlap = VK_BLEND_OVERLAP_UNCORRELATED_EXT;
color_blend_advanced.clampResults = VK_FALSE;
vk::CmdSetColorBlendAdvancedEXT(m_command_buffer, i, 1u, &color_blend_advanced);
}
vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u);
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DynamicBlendMix) {
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEquation);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendAdvanced);
RETURN_IF_SKIP(Init());
vkt::Image image_0(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::Image image_1(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView image_view_0 = image_0.CreateView();
vkt::ImageView image_view_1 = image_1.CreateView();
VkRenderingAttachmentInfo color_attachments[2];
color_attachments[0] = vku::InitStructHelper();
color_attachments[0].imageView = image_view_0;
color_attachments[0].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachments[1] = vku::InitStructHelper();
color_attachments[1].imageView = image_view_1;
color_attachments[1].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkPipelineColorBlendAttachmentState color_blend[2] = {};
color_blend[0] = DefaultColorBlendAttachmentState();
color_blend[1] = DefaultColorBlendAttachmentState();
VkFormat color_formats[2] = {VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM};
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 2;
pipeline_rendering_info.pColorAttachmentFormats = color_formats;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT);
pipe.cb_ci_.attachmentCount = 2;
pipe.cb_ci_.pAttachments = color_blend;
pipe.CreateGraphicsPipeline();
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea = {{0, 0}, {32, 32}};
rendering_info.layerCount = 1;
rendering_info.colorAttachmentCount = 2;
rendering_info.pColorAttachments = color_attachments;
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
VkColorBlendEquationEXT equation = {VK_BLEND_FACTOR_SRC_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_OP_ADD,
VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD};
VkColorBlendAdvancedEXT advanced = {VK_BLEND_OP_ADD, VK_FALSE, VK_FALSE, VK_BLEND_OVERLAP_UNCORRELATED_EXT, VK_FALSE};
vk::CmdSetColorBlendEquationEXT(m_command_buffer, 0, 1, &equation);
vk::CmdSetColorBlendAdvancedEXT(m_command_buffer, 1, 1, &advanced);
vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u);
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DynamicSampleLocationsRasterizationSamplesMismatch) {
TEST_DESCRIPTION("Dynamically set sample locations and rasterizationSamples that dont match");
AddRequiredExtensions(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3RasterizationSamples);
AddRequiredFeature(vkt::Feature::extendedDynamicState3SampleLocationsEnable);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_ENABLE_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdSetSampleLocationsEnableEXT(m_command_buffer, VK_FALSE);
vk::CmdSetRasterizationSamplesEXT(m_command_buffer, VK_SAMPLE_COUNT_1_BIT);
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(PositiveDynamicState, DepthClampControl) {
AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::depthClampControl);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
VkDepthClampRangeEXT clamp_range = {0.0f, 1.0f};
vk::CmdSetDepthClampRangeEXT(m_command_buffer, VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT, &clamp_range);
vk::CmdDraw(m_command_buffer, 3u, 1u, 0u, 0u);
vk::CmdSetDepthClampRangeEXT(m_command_buffer, VK_DEPTH_CLAMP_MODE_VIEWPORT_RANGE_EXT, nullptr);
vk::CmdDraw(m_command_buffer, 3u, 1u, 0u, 0u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, MultisampledRenderToSingleSampled) {
TEST_DESCRIPTION("https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/6921");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3RasterizationSamples);
AddRequiredFeature(vkt::Feature::multisampledRenderToSingleSampled);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkPipelineMultisampleStateCreateInfo ms_state_ci = vku::InitStructHelper();
ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_2_BIT; // is ignored since dynamic
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT);
pipe.ms_ci_ = ms_state_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::CmdSetRasterizationSamplesEXT(m_command_buffer, VK_SAMPLE_COUNT_4_BIT);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DiscardRectanglesModeNotSetWithZeroCount) {
AddRequiredExtensions(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
if (!DeviceExtensionSupported(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME, 2)) {
GTEST_SKIP() << "need VK_EXT_discard_rectangles version 2";
}
InitRenderTarget();
VkRect2D discard_rectangle = {{0, 0}, {16, 16}};
VkPipelineDiscardRectangleStateCreateInfoEXT discard_rect_ci = vku::InitStructHelper();
discard_rect_ci.discardRectangleCount = 0; // implicitly set discardRectangleEnable to FALSE
discard_rect_ci.pDiscardRectangles = &discard_rectangle;
CreatePipelineHelper pipe(*this, &discard_rect_ci);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DISCARD_RECTANGLE_MODE_EXT);
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();
}
TEST_F(PositiveDynamicState, DiscardRectanglesModeNotSetWithCommand) {
AddRequiredExtensions(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
if (!DeviceExtensionSupported(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME, 2)) {
GTEST_SKIP() << "need VK_EXT_discard_rectangles version 2";
}
InitRenderTarget();
VkRect2D discard_rectangle = {{0, 0}, {16, 16}};
VkPipelineDiscardRectangleStateCreateInfoEXT discard_rect_ci = vku::InitStructHelper();
discard_rect_ci.discardRectangleCount = 1;
discard_rect_ci.pDiscardRectangles = &discard_rectangle;
CreatePipelineHelper pipe(*this, &discard_rect_ci);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DISCARD_RECTANGLE_ENABLE_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DISCARD_RECTANGLE_MODE_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdSetDiscardRectangleEnableEXT(m_command_buffer, false);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DiscardRectanglesDisabled) {
TEST_DESCRIPTION("Draw without discard rectangles if discard rectangle enable is false");
AddRequiredExtensions(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DISCARD_RECTANGLE_ENABLE_EXT);
pipe.AddDynamicState(VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdSetDiscardRectangleEnableEXT(m_command_buffer, VK_FALSE);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DrawNotSetRasterizationStream) {
TEST_DESCRIPTION("Set VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT but without a geometry shader in the pipeline");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::geometryStreams);
AddRequiredFeature(vkt::Feature::extendedDynamicState3RasterizationStream);
AddRequiredFeature(vkt::Feature::transformFeedback);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
// never called vkCmdSetRasterizationStreamEXT
vk::CmdDraw(m_command_buffer, 1, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DrawNotSetTessellationDomainOrigin) {
TEST_DESCRIPTION("Set VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT but without a tese shader in the pipeline");
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3TessellationDomainOrigin);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkPipelineTessellationDomainOriginStateCreateInfo tess_domain_ci = vku::InitStructHelper();
tess_domain_ci.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
VkPipelineTessellationStateCreateInfo tess_ci = vku::InitStructHelper(&tess_domain_ci);
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT);
pipe.gp_ci_.pTessellationState = &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);
// vkCmdSetTessellationDomainOriginEXT not set
vk::CmdDraw(m_command_buffer, 1, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, VertexInputLocationMissing) {
TEST_DESCRIPTION("Shader uses a location not provided with dynamic vertex input");
AddRequiredExtensions(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::vertexInputDynamicState);
AddRequiredFeature(vkt::Feature::maintenance9);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
layout(location = 0) in vec4 x;
layout(location = 1) in vec4 y;
layout(location = 0) out vec4 c;
void main() {
c = x * y;
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()};
pipe.AddDynamicState(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vkt::Buffer buffer(*m_device, 16, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
VkDeviceSize offset = 0u;
vk::CmdBindVertexBuffers(m_command_buffer, 0u, 1u, &buffer.handle(), &offset);
VkVertexInputBindingDescription2EXT vertexInputBindingDescription = vku::InitStructHelper();
vertexInputBindingDescription.binding = 0u;
vertexInputBindingDescription.stride = sizeof(float) * 4;
vertexInputBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
vertexInputBindingDescription.divisor = 1u;
VkVertexInputAttributeDescription2EXT vertexAttributeDescription = vku::InitStructHelper();
vertexAttributeDescription.location = 0u;
vertexAttributeDescription.binding = 0u;
vertexAttributeDescription.format = VK_FORMAT_R32G32B32A32_SFLOAT;
vertexAttributeDescription.offset = 0u;
vk::CmdSetVertexInputEXT(m_command_buffer, 1u, &vertexInputBindingDescription, 1u, &vertexAttributeDescription);
vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, LineRasterization) {
AddRequiredExtensions(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3LineRasterizationMode);
AddRequiredFeature(vkt::Feature::bresenhamLines);
RETURN_IF_SKIP(Init());
InitRenderTarget();
// Valid because the topology is triangle here
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT);
pipe.ms_ci_.alphaToCoverageEnable = VK_TRUE;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdSetLineRasterizationModeEXT(m_command_buffer, VK_LINE_RASTERIZATION_MODE_BRESENHAM);
vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DrawNotSetLineRasterizationMode) {
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3LineRasterizationMode);
RETURN_IF_SKIP(Init());
InitRenderTarget();
// Valid because the topology is triangle here
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT);
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, 1, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, DrawNotSetLineStippleEnable) {
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3LineStippleEnable);
AddRequiredFeature(vkt::Feature::stippledRectangularLines);
RETURN_IF_SKIP(Init());
InitRenderTarget();
// Valid because the topology is triangle here
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT);
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, 1, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, ColorBlendEnableNotSet) {
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable);
RETURN_IF_SKIP(Init());
// Subpass has zero color attachments so we can ignore setting vkCmdSetColorBlendEnableEXT
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
VkRenderPassCreateInfo render_pass_ci = vku::InitStructHelper();
render_pass_ci.subpassCount = 1u;
render_pass_ci.pSubpasses = &subpass;
vkt::RenderPass render_pass(*m_device, render_pass_ci);
vkt::Framebuffer framebuffer(*m_device, render_pass, 0, nullptr);
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT);
pipe.gp_ci_.renderPass = render_pass;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(render_pass, framebuffer, 32u, 32u);
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();
}
TEST_F(PositiveDynamicState, SampleLocations) {
TEST_DESCRIPTION("Test invalid cases of VK_EXT_sample_location");
AddRequiredExtensions(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceSampleLocationsPropertiesEXT sample_locations_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(sample_locations_props);
if ((sample_locations_props.sampleLocationSampleCounts & VK_SAMPLE_COUNT_1_BIT) == 0) {
GTEST_SKIP() << "VK_SAMPLE_COUNT_1_BIT sampleLocationSampleCounts is not supported";
}
const VkFormat stencil_format = FindSupportedStencilOnlyFormat(Gpu());
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.format = stencil_format;
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.extent = {128, 128, 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_DEPTH_STENCIL_ATTACHMENT_BIT;
vkt::Image stencil_image(*m_device, image_create_info, vkt::set_layout);
vkt::Image color_image(*m_device, 128, 128, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentDescription(stencil_format, 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();
// Create a framebuffer
vkt::ImageView color_view = color_image.CreateView();
vkt::ImageView stencil_view = stencil_image.CreateView(VK_IMAGE_ASPECT_STENCIL_BIT);
const std::array<VkImageView, 2> attachments = {color_view, stencil_view};
vkt::Framebuffer fb(*m_device, rp, static_cast<uint32_t>(attachments.size()), attachments.data(), 128, 128);
VkMultisamplePropertiesEXT multisample_prop = vku::InitStructHelper();
vk::GetPhysicalDeviceMultisamplePropertiesEXT(Gpu(), VK_SAMPLE_COUNT_1_BIT, &multisample_prop);
// 1 from VK_SAMPLE_COUNT_1_BIT
const uint32_t valid_count =
multisample_prop.maxSampleLocationGridSize.width * multisample_prop.maxSampleLocationGridSize.height * 1;
if (valid_count <= 1) {
GTEST_SKIP() << "Need a maxSampleLocationGridSize width x height greater than 1";
}
std::vector<VkSampleLocationEXT> sample_location(valid_count, {0.5, 0.5});
VkSampleLocationsInfoEXT sample_locations_info = vku::InitStructHelper();
sample_locations_info.sampleLocationsPerPixel = VK_SAMPLE_COUNT_1_BIT;
sample_locations_info.sampleLocationGridSize = multisample_prop.maxSampleLocationGridSize;
sample_locations_info.sampleLocationsCount = valid_count;
sample_locations_info.pSampleLocations = sample_location.data();
VkPipelineSampleLocationsStateCreateInfoEXT sample_location_state = vku::InitStructHelper();
sample_location_state.sampleLocationsEnable = VK_TRUE;
sample_location_state.sampleLocationsInfo = sample_locations_info;
VkPipelineMultisampleStateCreateInfo pipe_ms_state_ci = vku::InitStructHelper(&sample_location_state);
pipe_ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
pipe_ms_state_ci.sampleShadingEnable = 0;
pipe_ms_state_ci.minSampleShading = 1.0;
pipe_ms_state_ci.pSampleMask = nullptr;
VkPipelineDepthStencilStateCreateInfo pipe_ds_state_ci = vku::InitStructHelper();
pipe_ds_state_ci.depthTestEnable = VK_TRUE;
pipe_ds_state_ci.stencilTestEnable = VK_FALSE;
// Creates valid pipelines with dynamic state
CreatePipelineHelper dynamic_pipe(*this);
dynamic_pipe.ms_ci_ = pipe_ms_state_ci;
dynamic_pipe.AddDynamicState(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
dynamic_pipe.gp_ci_.renderPass = rp;
dynamic_pipe.gp_ci_.pDepthStencilState = &pipe_ds_state_ci;
dynamic_pipe.CreateGraphicsPipeline();
vkt::Buffer vbo(*m_device, sizeof(float) * 3, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(rp, fb, 128, 128);
vk::CmdBindVertexBuffers(m_command_buffer, 1, 1, &vbo.handle(), &kZeroDeviceSize);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, dynamic_pipe);
vk::CmdSetSampleLocationsEXT(m_command_buffer, &sample_locations_info);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDynamicState, MeshPipelineInvalidtion) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8378");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState2);
AddRequiredFeature(vkt::Feature::meshShader);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT);
pipe.CreateGraphicsPipeline();
VkShaderObj ms(*m_device, kMeshMinimalGlsl, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2);
CreatePipelineHelper mesh_pipe(*this);
mesh_pipe.shader_stages_ = {ms.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()};
mesh_pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdSetPrimitiveRestartEnableEXT(m_command_buffer, VK_TRUE);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, mesh_pipe);
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();
}
TEST_F(PositiveDynamicState, UnusedFragmentShaderState) {
TEST_DESCRIPTION("mimics dEQP-VK.shader_object.misc.state.pipeline.vert.alphaToOne.disabled");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable);
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT); // tied to frag shader
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo()};
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
// never call vkCmdSetColorBlendEnableEXT
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();
}
TEST_F(PositiveDynamicState, DepthWriteFromVertexShader) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7858");
RETURN_IF_SKIP(Init());
InitRenderTarget();
CreatePipelineHelper pipe(*this);
pipe.AddDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo()};
pipe.rs_state_ci_.rasterizerDiscardEnable = VK_TRUE;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
float blends[4] = {1.0f, 1.0f, 1.0f, 1.0f};
vk::CmdSetBlendConstants(m_command_buffer, blends);
vk::CmdDraw(m_command_buffer, 1, 0, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}