blob: 2cac7ea93725b749ce5bb99f27ef26c096b5f470 [file] [log] [blame]
/*
* Copyright (c) 2015-2023 The Khronos Group Inc.
* Copyright (c) 2015-2023 Valve Corporation
* Copyright (c) 2015-2023 LunarG, Inc.
* Copyright (c) 2015-2023 Google, Inc.
* Modifications Copyright (C) 2020-2022 Advanced Micro Devices, Inc. All rights reserved.
* Modifications Copyright (C) 2021 ARM, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include "utils/cast_utils.h"
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
TEST_F(NegativeMultiview, MaxInstanceIndex) {
TEST_DESCRIPTION("Verify if instance index in CmdDraw is greater than maxMultiviewInstanceIndex.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceMultiviewFeatures multiview_features = vku::InitStructHelper();
multiview_features.multiview = VK_TRUE;
VkPhysicalDeviceFeatures2 pd_features2 = vku::InitStructHelper(&multiview_features);
RETURN_IF_SKIP(InitState(nullptr, &pd_features2));
InitRenderTarget();
VkPhysicalDeviceMultiviewProperties multiview_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(multiview_props);
if (multiview_props.maxMultiviewInstanceIndex == std::numeric_limits<uint32_t>::max()) {
GTEST_SKIP() << "maxMultiviewInstanceIndex is uint32_t max";
}
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.CreateGraphicsPipeline();
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "VUID-vkCmdDraw-maxMultiviewInstanceIndex-02688");
vk::CmdDraw(m_commandBuffer->handle(), 1, multiview_props.maxMultiviewInstanceIndex + 1, 0, 0);
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
TEST_F(NegativeMultiview, ClearColorAttachments) {
TEST_DESCRIPTION("Test cmdClearAttachments with active render pass that uses multiview");
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceMultiviewFeatures multiview_features = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(multiview_features);
if (!multiview_features.multiview) {
GTEST_SKIP() << "VkPhysicalDeviceMultiviewFeatures::multiview not supported";
}
RETURN_IF_SKIP(InitState(nullptr, &features2))
InitRenderTarget();
VkAttachmentDescription attachmentDescription = {};
attachmentDescription.format = VK_FORMAT_R8G8B8A8_UNORM;
attachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
attachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachmentDescription.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkAttachmentReference colorAttachmentReference = {};
colorAttachmentReference.layout = VK_IMAGE_LAYOUT_GENERAL;
colorAttachmentReference.attachment = 0;
VkSubpassDescription subpassDescription = {};
subpassDescription.colorAttachmentCount = 1;
subpassDescription.pColorAttachments = &colorAttachmentReference;
uint32_t viewMask = 0x1u;
VkRenderPassMultiviewCreateInfo renderPassMultiviewCreateInfo = vku::InitStructHelper();
renderPassMultiviewCreateInfo.subpassCount = 1;
renderPassMultiviewCreateInfo.pViewMasks = &viewMask;
VkRenderPassCreateInfo renderPassCreateInfo = vku::InitStructHelper(&renderPassMultiviewCreateInfo);
renderPassCreateInfo.attachmentCount = 1;
renderPassCreateInfo.pAttachments = &attachmentDescription;
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpassDescription;
vkt::RenderPass renderPass(*m_device, renderPassCreateInfo);
ASSERT_TRUE(renderPass.initialized());
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM;
image_create_info.extent.width = 32;
image_create_info.extent.height = 32;
image_create_info.extent.depth = 1;
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 4;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
image_create_info.flags = 0;
VkImageObj image(m_device);
image.Init(image_create_info);
VkImageView imageView = image.targetView(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0,
VK_REMAINING_ARRAY_LAYERS, VK_IMAGE_VIEW_TYPE_2D_ARRAY);
VkFramebufferCreateInfo framebufferCreateInfo = vku::InitStructHelper();
framebufferCreateInfo.width = 32;
framebufferCreateInfo.height = 32;
framebufferCreateInfo.layers = 1;
framebufferCreateInfo.renderPass = renderPass.handle();
framebufferCreateInfo.attachmentCount = 1;
framebufferCreateInfo.pAttachments = &imageView;
vkt::Framebuffer framebuffer(*m_device, framebufferCreateInfo);
ASSERT_TRUE(framebuffer.initialized());
// Start no RenderPass
m_commandBuffer->begin();
VkClearAttachment color_attachment;
color_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
color_attachment.clearValue.color.float32[0] = 0;
color_attachment.clearValue.color.float32[1] = 0;
color_attachment.clearValue.color.float32[2] = 0;
color_attachment.clearValue.color.float32[3] = 0;
color_attachment.colorAttachment = 0;
VkClearRect clear_rect = {};
clear_rect.rect.extent.width = 32;
clear_rect.rect.extent.height = 32;
VkRenderPassBeginInfo render_pass_begin_info = vku::InitStructHelper();
render_pass_begin_info.renderPass = renderPass.handle();
render_pass_begin_info.framebuffer = framebuffer.handle();
render_pass_begin_info.renderArea.extent.width = 32;
render_pass_begin_info.renderArea.extent.height = 32;
vk::CmdBeginRenderPass(m_commandBuffer->handle(), &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdClearAttachments-baseArrayLayer-00018");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdClearAttachments-pRects-06937");
clear_rect.layerCount = 2;
vk::CmdClearAttachments(m_commandBuffer->handle(), 1, &color_attachment, 1, &clear_rect);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdClearAttachments-baseArrayLayer-00018");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdClearAttachments-pRects-06937");
clear_rect.baseArrayLayer = 1;
clear_rect.layerCount = 1;
vk::CmdClearAttachments(m_commandBuffer->handle(), 1, &color_attachment, 1, &clear_rect);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeMultiview, UnboundResourcesAfterBeginRenderPassAndNextSubpass) {
TEST_DESCRIPTION(
"Validate all required resources are bound if multiview is enabled after vkCmdBeginRenderPass and vkCmdNextSubpass");
constexpr unsigned multiview_count = 2u;
constexpr unsigned extra_subpass_count = multiview_count - 1u;
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceMultiviewFeatures multiview_features = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(multiview_features);
if (multiview_features.multiview == VK_FALSE) {
GTEST_SKIP() << "Device does not support multiview.";
}
RETURN_IF_SKIP(InitState(nullptr, &features2, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
VkAttachmentDescription attachmentDescription = {};
attachmentDescription.format = VK_FORMAT_R8G8B8A8_UNORM;
attachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
attachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachmentDescription.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkAttachmentReference colorAttachmentReference = {};
colorAttachmentReference.layout = VK_IMAGE_LAYOUT_GENERAL;
colorAttachmentReference.attachment = 0;
m_renderPass_subpasses.resize(multiview_count);
for (unsigned i = 0; i < multiview_count; ++i) {
m_renderPass_subpasses[i].colorAttachmentCount = 1;
m_renderPass_subpasses[i].pColorAttachments = &colorAttachmentReference;
}
uint32_t viewMasks[multiview_count] = {};
for (unsigned i = 0; i < multiview_count; ++i) {
viewMasks[i] = 1u << i;
}
VkRenderPassMultiviewCreateInfo renderPassMultiviewCreateInfo = vku::InitStructHelper();
renderPassMultiviewCreateInfo.subpassCount = multiview_count;
renderPassMultiviewCreateInfo.pViewMasks = viewMasks;
m_renderPass_info = vku::InitStructHelper(&renderPassMultiviewCreateInfo);
m_renderPass_info.attachmentCount = 1;
m_renderPass_info.pAttachments = &attachmentDescription;
m_renderPass_info.subpassCount = m_renderPass_subpasses.size();
m_renderPass_info.pSubpasses = m_renderPass_subpasses.data();
m_renderPass_dependencies.resize(extra_subpass_count);
for (unsigned i = 0; i < m_renderPass_dependencies.size(); ++i) {
auto &subpass_dep = m_renderPass_dependencies[i];
subpass_dep.srcSubpass = i;
subpass_dep.dstSubpass = i + 1;
subpass_dep.srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpass_dep.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpass_dep.srcAccessMask = VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
subpass_dep.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT |
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
subpass_dep.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
}
m_renderPass_info.dependencyCount = static_cast<uint32_t>(m_renderPass_dependencies.size());
m_renderPass_info.pDependencies = m_renderPass_dependencies.data();
vk::CreateRenderPass(m_device->handle(), &m_renderPass_info, nullptr, &m_renderPass);
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM;
image_create_info.extent.width = m_width;
image_create_info.extent.height = m_height;
image_create_info.extent.depth = 1;
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = multiview_count;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
image_create_info.flags = 0;
VkImageObj image(m_device);
image.Init(image_create_info);
image.SetLayout(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL);
VkImageView imageView = image.targetView(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0,
VK_REMAINING_ARRAY_LAYERS, VK_IMAGE_VIEW_TYPE_2D_ARRAY);
VkFramebufferCreateInfo framebufferCreateInfo = vku::InitStructHelper();
framebufferCreateInfo.width = m_width;
framebufferCreateInfo.height = m_height;
framebufferCreateInfo.layers = 1;
framebufferCreateInfo.renderPass = m_renderPass;
framebufferCreateInfo.attachmentCount = 1;
framebufferCreateInfo.pAttachments = &imageView;
vk::CreateFramebuffer(m_device->device(), &framebufferCreateInfo, nullptr, &m_framebuffer);
VkClearValue clear{};
clear.color = m_clear_color;
m_renderPassClearValues.emplace_back(clear);
m_renderPassBeginInfo.renderPass = m_renderPass;
m_renderPassBeginInfo.framebuffer = m_framebuffer;
m_renderPassBeginInfo.renderArea.extent.width = m_width;
m_renderPassBeginInfo.renderArea.extent.height = m_height;
m_renderPassBeginInfo.clearValueCount = m_renderPassClearValues.size();
m_renderPassBeginInfo.pClearValues = m_renderPassClearValues.data();
// Pipeline not bound test
{
// No need to create individual pipelines for each subpass since we are checking no bound pipeline
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.CreateGraphicsPipeline();
m_commandBuffer->begin();
// This bind should not be valid after we begin the renderpass
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-None-08606");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
for (unsigned i = 0; i < extra_subpass_count; ++i) {
// This bind should not be valid for next subpass
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_commandBuffer->NextSubpass();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-None-08606");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
}
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
m_commandBuffer->reset();
// Dynamic state (checking with line width)
{
// Pipeline for subpass 0
CreatePipelineHelper pipe(*this);
pipe.ia_ci_.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
pipe.AddDynamicState(VK_DYNAMIC_STATE_LINE_WIDTH);
pipe.InitState();
pipe.CreateGraphicsPipeline();
// Pipelines for all other subpasses
vkt::Pipeline pipelines[extra_subpass_count];
for (unsigned i = 0; i < extra_subpass_count; ++i) {
auto pipe_info = pipe.gp_ci_;
pipe_info.subpass = i + 1;
pipelines[i].init(*m_device, pipe_info);
}
m_commandBuffer->begin();
// This line width set should not be valid for next subpass
vk::CmdSetLineWidth(m_commandBuffer->handle(), 1.0f);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-None-07833");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
for (unsigned i = 0; i < extra_subpass_count; ++i) {
// This line width set should not be valid for next subpass
vk::CmdSetLineWidth(m_commandBuffer->handle(), 1.0f);
m_commandBuffer->NextSubpass();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[i].handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-None-07833");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
}
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
m_commandBuffer->reset();
// Push constants
{
char const *const vsSource = R"glsl(
#version 450
layout(push_constant, std430) uniform foo {
mat3 m;
} constants;
void main(){
vec3 v3 = constants.m[0];
}
)glsl";
VkShaderObj const vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj const fs(this, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPushConstantRange push_constant_range = {VK_SHADER_STAGE_VERTEX_BIT, 0, 36};
VkPipelineLayoutCreateInfo pipeline_layout_info = vku::InitStructHelper();
pipeline_layout_info.pushConstantRangeCount = 1;
pipeline_layout_info.pPushConstantRanges = &push_constant_range;
vkt::PipelineLayout layout(*m_device, pipeline_layout_info, std::vector<const vkt::DescriptorSetLayout *>{});
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.pipeline_layout_ci_ = pipeline_layout_info;
pipe.InitState();
pipe.CreateGraphicsPipeline();
// Pipelines for all other subpasses
vkt::Pipeline pipelines[extra_subpass_count];
for (unsigned i = 0; i < extra_subpass_count; ++i) {
auto pipe_info = pipe.gp_ci_;
pipe_info.subpass = i + 1;
pipelines[i].init(*m_device, pipe_info);
}
// Set up complete
const float dummy_values[16] = {};
m_commandBuffer->begin();
// This push constants should not be counted when render pass begins
vk::CmdPushConstants(m_commandBuffer->handle(), layout.handle(), VK_SHADER_STAGE_VERTEX_BIT, push_constant_range.offset,
push_constant_range.size, dummy_values);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-maintenance4-08602");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
for (unsigned i = 0; i < extra_subpass_count; ++i) {
// This push constants should not be counted when we change subpass
vk::CmdPushConstants(m_commandBuffer->handle(), layout.handle(), VK_SHADER_STAGE_VERTEX_BIT, push_constant_range.offset,
push_constant_range.size, dummy_values);
m_commandBuffer->NextSubpass();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[i].handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-maintenance4-08602");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
}
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
m_commandBuffer->reset();
// Descriptor sets
{
OneOffDescriptorSet descriptor_set{m_device, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}}};
VkBufferCreateInfo bci = vku::InitStructHelper();
bci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
bci.size = 8;
vkt::Buffer buffer(*m_device, bci);
VkDescriptorBufferInfo buffer_info;
buffer_info.buffer = buffer.handle();
buffer_info.offset = 0;
buffer_info.range = VK_WHOLE_SIZE;
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = descriptor_set.set_;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.pBufferInfo = &buffer_info;
vk::UpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL);
VkPipelineLayoutCreateInfo pipeline_layout_info = vku::InitStructHelper();
pipeline_layout_info.setLayoutCount = 1;
pipeline_layout_info.pSetLayouts = &descriptor_set.layout_.handle();
vkt::PipelineLayout layout(*m_device, pipeline_layout_info, std::vector<vkt::DescriptorSetLayout const *>{});
VkShaderObj const vs(this, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj const fs(this, kFragmentUniformGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.pipeline_layout_ci_ = pipeline_layout_info;
pipe.InitState();
pipe.CreateGraphicsPipeline();
// Pipelines for all other subpasses
vkt::Pipeline pipelines[extra_subpass_count];
for (unsigned i = 0; i < extra_subpass_count; ++i) {
auto pipe_info = pipe.gp_ci_;
pipe_info.subpass = i + 1;
pipelines[i].init(*m_device, pipe_info);
}
// Set up complete
m_commandBuffer->begin();
// This descriptor bind should not be counted when render pass begins
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_.handle(), 0, 1,
&descriptor_set.set_, 0, nullptr);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-None-08600");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
for (unsigned i = 0; i < extra_subpass_count; ++i) {
// This descriptor bind should not be counted when next subpass begins
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_.handle(), 0,
1, &descriptor_set.set_, 0, nullptr);
m_commandBuffer->NextSubpass();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[i].handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-None-08600");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
}
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
m_commandBuffer->reset();
// Vertex buffer
{
float const vertex_data[] = {1.0f, 0.0f};
vkt::Buffer vbo(*m_device, sizeof(vertex_data), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
VkVertexInputBindingDescription input_binding{};
input_binding.binding = 0;
input_binding.stride = sizeof(vertex_data);
input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
VkVertexInputAttributeDescription input_attribs{};
input_attribs.binding = 0;
input_attribs.location = 0;
input_attribs.format = VK_FORMAT_R32G32_SFLOAT;
input_attribs.offset = 0;
char const *const vsSource = R"glsl(
#version 450
layout(location = 0) in vec2 input0;
void main(){
gl_Position = vec4(input0.x, input0.y, 0.0f, 1.0f);
}
)glsl";
VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(this, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.vi_ci_.vertexBindingDescriptionCount = 1;
pipe.vi_ci_.pVertexBindingDescriptions = &input_binding;
pipe.vi_ci_.vertexAttributeDescriptionCount = 1;
pipe.vi_ci_.pVertexAttributeDescriptions = &input_attribs;
pipe.InitState();
pipe.CreateGraphicsPipeline();
// Pipelines for all other subpasses
vkt::Pipeline pipelines[extra_subpass_count];
for (unsigned i = 0; i < extra_subpass_count; ++i) {
auto pipe_info = pipe.gp_ci_;
pipe_info.subpass = i + 1;
pipelines[i].init(*m_device, pipe_info);
}
// Set up complete
VkDeviceSize offset = 0;
m_commandBuffer->begin();
// This vertex buffer bind should not be counted when render pass begins
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-None-04007");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-None-02721");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
for (unsigned i = 0; i < extra_subpass_count; ++i) {
// This vertex buffer bind should not be counted when next subpass begins
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
m_commandBuffer->NextSubpass();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[i].handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-None-04007");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-None-02721");
vk::CmdDraw(m_commandBuffer->handle(), 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
}
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
m_commandBuffer->reset();
// Index buffer
{
float const vertex_data[] = {1.0f, 0.0f};
vkt::Buffer vbo(*m_device, sizeof(vertex_data), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
uint32_t const index_data[] = {0};
vkt::Buffer ibo(*m_device, sizeof(index_data), VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
VkVertexInputBindingDescription input_binding{};
input_binding.binding = 0;
input_binding.stride = sizeof(vertex_data);
input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
VkVertexInputAttributeDescription input_attribs{};
input_attribs.binding = 0;
input_attribs.location = 0;
input_attribs.format = VK_FORMAT_R32G32_SFLOAT;
input_attribs.offset = 0;
char const *const vsSource = R"glsl(
#version 450
layout(location = 0) in vec2 input0;
void main(){
gl_Position = vec4(input0.x, input0.y, 0.0f, 1.0f);
}
)glsl";
VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(this, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.vi_ci_.vertexBindingDescriptionCount = 1;
pipe.vi_ci_.pVertexBindingDescriptions = &input_binding;
pipe.vi_ci_.vertexAttributeDescriptionCount = 1;
pipe.vi_ci_.pVertexAttributeDescriptions = &input_attribs;
pipe.InitState();
pipe.CreateGraphicsPipeline();
// Pipelines for all other subpasses
vkt::Pipeline pipelines[extra_subpass_count];
for (unsigned i = 0; i < extra_subpass_count; ++i) {
auto pipe_info = pipe.gp_ci_;
pipe_info.subpass = i + 1;
pipelines[i].init(*m_device, pipe_info);
}
// Set up complete
VkDeviceSize offset = 0;
m_commandBuffer->begin();
// This index buffer bind should not be counted when render pass begins
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), ibo.handle(), 0, VK_INDEX_TYPE_UINT32);
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndexed-None-07312");
vk::CmdDrawIndexed(m_commandBuffer->handle(), 0, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
for (unsigned i = 0; i < extra_subpass_count; ++i) {
// This index buffer bind should not be counted when next subpass begins
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), ibo.handle(), 0, VK_INDEX_TYPE_UINT32);
m_commandBuffer->NextSubpass();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[i].handle());
vk::CmdBindVertexBuffers(m_commandBuffer->handle(), 0, 1, &vbo.handle(), &offset);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndexed-None-07312");
vk::CmdDrawIndexed(m_commandBuffer->handle(), 0, 1, 0, 0, 0);
m_errorMonitor->VerifyFound();
}
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
}
TEST_F(NegativeMultiview, BeginTransformFeedback) {
TEST_DESCRIPTION("Test beginning transform feedback in a render pass with multiview enabled");
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceMultiviewFeaturesKHR mv_features = vku::InitStructHelper();
VkPhysicalDeviceTransformFeedbackFeaturesEXT tf_features = vku::InitStructHelper(&mv_features);
auto pd_features = GetPhysicalDeviceFeatures2(tf_features);
if (!tf_features.transformFeedback) {
GTEST_SKIP() << "transformFeedback not supported; skipped.";
}
if (!mv_features.multiview) {
GTEST_SKIP() << "multiview not supported.";
}
RETURN_IF_SKIP(InitState(nullptr, &pd_features));
InitRenderTarget();
VkAttachmentDescription attachmentDescription = {};
attachmentDescription.format = VK_FORMAT_R8G8B8A8_UNORM;
attachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
attachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachmentDescription.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkAttachmentReference colorAttachmentReference = {};
colorAttachmentReference.layout = VK_IMAGE_LAYOUT_GENERAL;
colorAttachmentReference.attachment = 0;
VkSubpassDescription subpassDescription = {};
subpassDescription.colorAttachmentCount = 1;
subpassDescription.pColorAttachments = &colorAttachmentReference;
uint32_t viewMask = 0x1u;
VkRenderPassMultiviewCreateInfo renderPassMultiviewCreateInfo = vku::InitStructHelper();
renderPassMultiviewCreateInfo.subpassCount = 1;
renderPassMultiviewCreateInfo.pViewMasks = &viewMask;
VkRenderPassCreateInfo renderPassCreateInfo = vku::InitStructHelper(&renderPassMultiviewCreateInfo);
renderPassCreateInfo.attachmentCount = 1;
renderPassCreateInfo.pAttachments = &attachmentDescription;
renderPassCreateInfo.subpassCount = 1;
renderPassCreateInfo.pSubpasses = &subpassDescription;
vkt::RenderPass render_pass;
render_pass.init(*m_device, renderPassCreateInfo);
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM;
image_create_info.extent.width = 32;
image_create_info.extent.height = 32;
image_create_info.extent.depth = 1;
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 4;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
image_create_info.flags = 0;
VkImageObj image(m_device);
image.Init(image_create_info);
auto image_view_ci = image.BasicViewCreatInfo();
image_view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
VkImageView imageView = image.targetView(image_view_ci);
VkFramebufferCreateInfo framebufferCreateInfo = vku::InitStructHelper();
framebufferCreateInfo.width = 32;
framebufferCreateInfo.height = 32;
framebufferCreateInfo.layers = 1;
framebufferCreateInfo.renderPass = render_pass.handle();
framebufferCreateInfo.attachmentCount = 1;
framebufferCreateInfo.pAttachments = &imageView;
vkt::Framebuffer framebuffer(*m_device, framebufferCreateInfo);
VkRenderPassBeginInfo render_pass_begin_info = vku::InitStructHelper();
render_pass_begin_info.renderPass = render_pass.handle();
render_pass_begin_info.framebuffer = framebuffer.handle();
render_pass_begin_info.renderArea.extent.width = 32;
render_pass_begin_info.renderArea.extent.height = 32;
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.CreateGraphicsPipeline();
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(render_pass_begin_info);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBeginTransformFeedbackEXT-None-04128");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBeginTransformFeedbackEXT-None-02373");
vk::CmdBeginTransformFeedbackEXT(m_commandBuffer->handle(), 0, 1, nullptr, nullptr);
m_errorMonitor->VerifyFound();
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
TEST_F(NegativeMultiview, Features) {
TEST_DESCRIPTION("Checks VK_KHR_multiview features.");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
std::vector<const char *> device_extensions;
device_extensions.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME);
VkPhysicalDeviceMultiviewFeatures multiview_features = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(multiview_features);
// Set false to trigger VUs
multiview_features.multiview = VK_FALSE;
vkt::PhysicalDevice physical_device(gpu());
vkt::QueueCreateInfoArray queue_info(physical_device.queue_properties_);
std::vector<VkDeviceQueueCreateInfo> create_queue_infos;
auto qci = queue_info.data();
for (uint32_t i = 0; i < queue_info.size(); ++i) {
if (qci[i].queueCount) {
create_queue_infos.push_back(qci[i]);
}
}
VkDeviceCreateInfo device_create_info = vku::InitStructHelper(&features2);
device_create_info.queueCreateInfoCount = queue_info.size();
device_create_info.pQueueCreateInfos = queue_info.data();
device_create_info.ppEnabledExtensionNames = device_extensions.data();
device_create_info.enabledExtensionCount = device_extensions.size();
VkDevice testDevice;
if ((multiview_features.multiviewGeometryShader == VK_FALSE) && (multiview_features.multiviewTessellationShader == VK_FALSE)) {
GTEST_SKIP() << "multiviewGeometryShader and multiviewTessellationShader feature not supported";
}
if (multiview_features.multiviewGeometryShader == VK_TRUE) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPhysicalDeviceMultiviewFeatures-multiviewGeometryShader-00580");
}
if (multiview_features.multiviewTessellationShader == VK_TRUE) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPhysicalDeviceMultiviewFeatures-multiviewTessellationShader-00581");
}
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeMultiview, RenderPassCreateOverlappingCorrelationMasks) {
TEST_DESCRIPTION("Create a subpass with overlapping correlation masks");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
AddOptionalExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
const bool rp2Supported = IsExtensionsEnabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
VkPhysicalDeviceMultiviewFeatures multiview_features = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(multiview_features);
if (multiview_features.multiview == VK_FALSE) {
GTEST_SKIP() << "multiview feature not supported";
}
RETURN_IF_SKIP(InitState(nullptr, &features2))
const VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr};
std::array viewMasks = {0x3u};
std::array correlationMasks = {0x1u, 0x2u};
auto rpmvci = vku::InitStruct<VkRenderPassMultiviewCreateInfo>(
nullptr, 1u, viewMasks.data(), 0u, nullptr, static_cast<uint32_t>(correlationMasks.size()), correlationMasks.data());
auto rpci = vku::InitStruct<VkRenderPassCreateInfo>(&rpmvci, 0u, 0u, nullptr, 1u, &subpass, 0u, nullptr);
PositiveTestRenderPassCreate(m_errorMonitor, *m_device, rpci, false);
// Correlation masks must not overlap
correlationMasks[1] = 0x3u;
TestRenderPassCreate(m_errorMonitor, *m_device, rpci, rp2Supported,
"VUID-VkRenderPassMultiviewCreateInfo-pCorrelationMasks-00841",
"VUID-VkRenderPassCreateInfo2-pCorrelatedViewMasks-03056");
// Check for more specific "don't set any correlation masks when multiview is not enabled"
if (rp2Supported) {
viewMasks[0] = 0;
correlationMasks[0] = 0;
correlationMasks[1] = 0;
safe_VkRenderPassCreateInfo2 safe_rpci2 = ConvertVkRenderPassCreateInfoToV2KHR(rpci);
TestRenderPass2KHRCreate(*m_errorMonitor, *m_device, *safe_rpci2.ptr(), {"VUID-VkRenderPassCreateInfo2-viewMask-03057"});
}
}
TEST_F(NegativeMultiview, RenderPassViewMasksNotEnough) {
TEST_DESCRIPTION("Create a subpass with the wrong number of view masks, or inconsistent setting of view masks");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
AddOptionalExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
const bool rp2Supported = IsExtensionsEnabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
VkPhysicalDeviceMultiviewFeatures multiview_features = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(multiview_features);
if (multiview_features.multiview == VK_FALSE) {
GTEST_SKIP() << "multiview feature not supported";
}
RETURN_IF_SKIP(InitState(nullptr, &features2))
VkSubpassDescription subpasses[] = {
{0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr},
{0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr},
};
uint32_t viewMasks[] = {0x3u, 0u};
auto rpmvci = vku::InitStruct<VkRenderPassMultiviewCreateInfo>(nullptr, 1u, viewMasks, 0u, nullptr, 0u, nullptr);
auto rpci = vku::InitStruct<VkRenderPassCreateInfo>(&rpmvci, 0u, 0u, nullptr, 2u, subpasses, 0u, nullptr);
// Not enough view masks
TestRenderPassCreate(m_errorMonitor, *m_device, rpci, rp2Supported, "VUID-VkRenderPassCreateInfo-pNext-01928",
"VUID-VkRenderPassCreateInfo2-viewMask-03058");
}
TEST_F(NegativeMultiview, RenderPassCreateSubpassMissingAttributesBitNVX) {
TEST_DESCRIPTION("Create a subpass with the VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX flag missing");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
AddOptionalExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
const bool rp2Supported = IsExtensionsEnabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
RETURN_IF_SKIP(InitState())
VkSubpassDescription subpasses[] = {
{VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr,
nullptr, 0, nullptr},
};
auto rpci = vku::InitStruct<VkRenderPassCreateInfo>(nullptr, 0u, 0u, nullptr, 1u, subpasses, 0u, nullptr);
TestRenderPassCreate(m_errorMonitor, *m_device, rpci, rp2Supported, "VUID-VkSubpassDescription-flags-00856",
"VUID-VkSubpassDescription2-flags-03076");
}
TEST_F(NegativeMultiview, DrawWithPipelineIncompatibleWithRenderPass) {
TEST_DESCRIPTION(
"Hit RenderPass incompatible cases: drawing with an active renderpass that's not compatible with the bound pipeline state "
"object's creation renderpass since only the former uses Multiview.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
AddOptionalExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
const bool rp2Supported = IsExtensionsEnabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
VkPhysicalDeviceMultiviewFeatures multiview_features = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(multiview_features);
if (!features2.features.multiViewport) {
GTEST_SKIP() << "multiViewport feature is not supported, skipping test.\n";
}
if (!multiview_features.multiview) {
GTEST_SKIP() << "multiview feature is not supported, skipping test.\n";
}
RETURN_IF_SKIP(InitState(nullptr, &features2, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
// Set up VkRenderPassCreateInfo struct used with VK_VERSION_1_0
VkAttachmentReference color_att = {};
color_att.layout = VK_IMAGE_LAYOUT_GENERAL;
VkAttachmentDescription attach = {};
attach.samples = VK_SAMPLE_COUNT_1_BIT;
attach.format = VK_FORMAT_B8G8R8A8_UNORM;
attach.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
attach.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_att;
uint32_t viewMasks[] = {0x3u};
VkRenderPassMultiviewCreateInfo rpmvci = vku::InitStructHelper();
rpmvci.subpassCount = 1;
rpmvci.pViewMasks = viewMasks;
VkRenderPassCreateInfo rpci = vku::InitStructHelper(&rpmvci);
rpci.attachmentCount = 1;
rpci.pAttachments = &attach;
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
// Set up VkRenderPassCreateInfo2 struct used with VK_VERSION_1_2
VkAttachmentReference2 color_att2 = vku::InitStructHelper();
color_att2.layout = VK_IMAGE_LAYOUT_GENERAL;
VkAttachmentDescription2 attach2 = vku::InitStructHelper();
attach2.samples = VK_SAMPLE_COUNT_1_BIT;
attach2.format = VK_FORMAT_B8G8R8A8_UNORM;
attach2.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
attach2.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkSubpassDescription2 subpass2 = vku::InitStructHelper();
subpass2.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass2.viewMask = 0x3u;
subpass2.colorAttachmentCount = 1;
subpass2.pColorAttachments = &color_att2;
VkRenderPassCreateInfo2 rpci2 = vku::InitStructHelper();
rpci2.attachmentCount = 1;
rpci2.pAttachments = &attach2;
rpci2.subpassCount = 1;
rpci2.pSubpasses = &subpass2;
// Create render passes with VK_VERSION_1_0 struct and vkCreateRenderPass call
// Create rp[0] with Multiview pNext, rp[1] without Multiview pNext, rp[2] with Multiview pNext but another viewMask
std::array<vkt::RenderPass, 3> rp;
rp[0].init(*m_device, rpci);
rpci.pNext = nullptr;
rp[1].init(*m_device, rpci);
uint32_t viewMasks2[] = {0x1u};
rpmvci.pViewMasks = viewMasks2;
rpci.pNext = &rpmvci;
rp[2].init(*m_device, rpci);
// Create render passes with VK_VERSION_1_2 struct and vkCreateRenderPass2KHR call
// Create rp2[0] with Multiview, rp2[1] without Multiview (zero viewMask), rp2[2] with Multiview but another viewMask
std::array<vkt::RenderPass, 3> rp2;
if (rp2Supported) {
rp2[0].init(*m_device, rpci2, true);
subpass2.viewMask = 0x0u;
rpci2.pSubpasses = &subpass2;
rp2[1].init(*m_device, rpci2, true);
subpass2.viewMask = 0x1u;
rpci2.pSubpasses = &subpass2;
rp2[2].init(*m_device, rpci2, true);
}
// Create image view
VkImageObj image(m_device);
auto ici2d = image.ImageCreateInfo2D(128, 128, 1, 2, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
VK_IMAGE_TILING_OPTIMAL, 0);
image.Init(ici2d);
ASSERT_TRUE(image.initialized());
VkImageViewCreateInfo ivci = vku::InitStructHelper();
ivci.image = image.handle();
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
ivci.format = VK_FORMAT_B8G8R8A8_UNORM;
ivci.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY};
ivci.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 2};
vkt::ImageView iv(*m_device, ivci);
// Create framebuffers for rp[0] and rp2[0]
VkFramebufferCreateInfo fbci = vku::InitStructHelper();
fbci.renderPass = rp[0].handle();
fbci.attachmentCount = 1;
fbci.pAttachments = &iv.handle();
fbci.width = 128;
fbci.height = 128;
fbci.layers = 1;
vkt::Framebuffer fb(*m_device, fbci);
vkt::Framebuffer fb2;
if (rp2Supported) {
fbci.renderPass = rp2[0].handle();
fb2.init(*m_device, fbci);
}
VkRenderPassBeginInfo rp_begin = vku::InitStructHelper();
rp_begin.renderPass = rp[0].handle();
rp_begin.framebuffer = fb.handle();
rp_begin.renderArea = {{0, 0}, {128, 128}};
// Create a graphics pipeline with rp[1]
CreatePipelineHelper pipe_1(*this);
pipe_1.InitState();
pipe_1.gp_ci_.layout = pipeline_layout.handle();
pipe_1.gp_ci_.renderPass = rp[1].handle();
pipe_1.CreateGraphicsPipeline();
// Create a graphics pipeline with rp[2]
CreatePipelineHelper pipe_2(*this);
pipe_2.InitState();
pipe_2.gp_ci_.layout = pipeline_layout.handle();
pipe_2.gp_ci_.renderPass = rp[2].handle();
pipe_2.CreateGraphicsPipeline();
CreatePipelineHelper pipe2_1(*this);
CreatePipelineHelper pipe2_2(*this);
if (rp2Supported) {
pipe2_1.InitState();
pipe2_1.gp_ci_.layout = pipeline_layout.handle();
pipe2_1.gp_ci_.renderPass = rp[1].handle();
pipe2_1.CreateGraphicsPipeline();
pipe2_2.InitState();
pipe2_2.gp_ci_.layout = pipeline_layout.handle();
pipe2_2.gp_ci_.renderPass = rp[2].handle();
pipe2_2.CreateGraphicsPipeline();
}
VkCommandBufferInheritanceInfo cbii = vku::InitStructHelper();
cbii.renderPass = rp[0].handle();
cbii.subpass = 0;
VkCommandBufferBeginInfo cbbi = vku::InitStructHelper();
cbbi.pInheritanceInfo = &cbii;
// Begin rp[0] for VK_VERSION_1_0 test cases
vk::BeginCommandBuffer(m_commandBuffer->handle(), &cbbi);
vk::CmdBeginRenderPass(m_commandBuffer->handle(), &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
// Bind rp[1]'s pipeline to command buffer
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_1.Handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-renderPass-02684");
// Render triangle (error on Multiview usage should trigger on draw)
vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
// Bind rp[2]'s pipeline to command buffer
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_2.Handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-renderPass-02684");
// Render triangle (error on non-matching viewMasks for Multiview usage should trigger on draw)
vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
// End rp[0]
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
// Begin rp2[0] for VK_VERSION_1_2 test cases
if (rp2Supported) {
cbii.renderPass = rp2[0].handle();
rp_begin.renderPass = rp2[0].handle();
rp_begin.framebuffer = fb2.handle();
vk::BeginCommandBuffer(m_commandBuffer->handle(), &cbbi);
vk::CmdBeginRenderPass(m_commandBuffer->handle(), &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
// Bind rp2[1]'s pipeline to command buffer
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2_1.Handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-renderPass-02684");
// Render triangle (error on Multiview usage should trigger on draw)
vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
// Bind rp2[2]'s pipeline to command buffer
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2_2.Handle());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-renderPass-02684");
// Render triangle (error on non-matching viewMasks for Multiview usage should trigger on draw)
vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
// End rp2[0]
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
}
TEST_F(NegativeMultiview, RenderPassViewMasksZero) {
TEST_DESCRIPTION("Create a render pass with some view masks 0 and some not 0");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
VkPhysicalDeviceMultiviewProperties render_pass_multiview_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(render_pass_multiview_props);
if (render_pass_multiview_props.maxMultiviewViewCount < 2) {
GTEST_SKIP() << "maxMultiviewViewCount lower than required";
}
VkSubpassDescription subpasses[2];
subpasses[0] = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr};
subpasses[1] = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr};
uint32_t viewMasks[] = {0x3u, 0x0};
uint32_t correlationMasks[] = {0x1u, 0x3u};
auto rpmvci = vku::InitStruct<VkRenderPassMultiviewCreateInfo>(nullptr, 2u, viewMasks, 0u, nullptr, 2u, correlationMasks);
auto rpci = vku::InitStruct<VkRenderPassCreateInfo>(&rpmvci, 0u, 0u, nullptr, 2u, subpasses, 0u, nullptr);
TestRenderPassCreate(m_errorMonitor, *m_device, rpci, false, "VUID-VkRenderPassCreateInfo-pNext-02513", nullptr);
}
TEST_F(NegativeMultiview, RenderPassViewOffsets) {
TEST_DESCRIPTION("Create a render pass with invalid multiview pViewOffsets");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
VkPhysicalDeviceMultiviewProperties render_pass_multiview_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(render_pass_multiview_props);
if (render_pass_multiview_props.maxMultiviewViewCount < 2) {
GTEST_SKIP() << "maxMultiviewViewCount lower than required";
}
VkSubpassDescription subpasses[2];
subpasses[0] = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr};
subpasses[1] = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr};
uint32_t viewMasks[] = {0x1u, 0x2u};
uint32_t correlationMasks[] = {0x1u, 0x2u};
int32_t view_offset = 1;
auto rpmvci = vku::InitStruct<VkRenderPassMultiviewCreateInfo>(nullptr, 2u, viewMasks, 1u, &view_offset, 2u, correlationMasks);
VkSubpassDependency dependency = {};
auto rpci = vku::InitStruct<VkRenderPassCreateInfo>(&rpmvci, 0u, 0u, nullptr, 2u, subpasses, 1u, &dependency);
TestRenderPassCreate(m_errorMonitor, *m_device, rpci, false, "VUID-VkRenderPassCreateInfo-pNext-02512", nullptr);
}
TEST_F(NegativeMultiview, RenderPassViewMasksLimit) {
TEST_DESCRIPTION("Create a render pass with invalid view mask");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
VkPhysicalDeviceMultiviewProperties render_pass_multiview_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(render_pass_multiview_props);
if (render_pass_multiview_props.maxMultiviewViewCount >= 32) {
GTEST_SKIP() << "maxMultiviewViewCount too high";
}
VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr};
uint32_t viewMask = 1 << render_pass_multiview_props.maxMultiviewViewCount;
uint32_t correlationMask = 0x1u;
auto rpmvci = vku::InitStruct<VkRenderPassMultiviewCreateInfo>(nullptr, 1u, &viewMask, 0u, nullptr, 1u, &correlationMask);
auto rpci = vku::InitStruct<VkRenderPassCreateInfo>(&rpmvci, 0u, 0u, nullptr, 1u, &subpass, 0u, nullptr);
TestRenderPassCreate(m_errorMonitor, *m_device, rpci, false, "VUID-VkRenderPassMultiviewCreateInfo-pViewMasks-06697", nullptr);
}
TEST_F(NegativeMultiview, FeaturesDisabled) {
TEST_DESCRIPTION("Create graphics pipeline using multiview features which are not enabled.");
SetTargetApiVersion(VK_API_VERSION_1_2);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceMultiviewFeatures multiview_features = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(multiview_features);
if (!multiview_features.multiview) {
GTEST_SKIP() << "Multiview support is required";
}
multiview_features.multiviewTessellationShader = VK_FALSE;
multiview_features.multiviewGeometryShader = VK_FALSE;
RETURN_IF_SKIP(InitState(nullptr, &features2))
VkAttachmentReference2 color_attachment = vku::InitStructHelper();
color_attachment.layout = VK_IMAGE_LAYOUT_GENERAL;
VkAttachmentDescription2 description = vku::InitStructHelper();
description.samples = VK_SAMPLE_COUNT_1_BIT;
description.format = VK_FORMAT_B8G8R8A8_UNORM;
description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkSubpassDescription2 subpass = vku::InitStructHelper();
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.viewMask = 0x3u;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_attachment;
VkRenderPassCreateInfo2 rpci = vku::InitStructHelper();
rpci.attachmentCount = 1;
rpci.pAttachments = &description;
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
vkt::RenderPass render_pass(*m_device, rpci);
ASSERT_TRUE(render_pass.initialized());
if (features2.features.tessellationShader) {
char const *tcsSource = R"glsl(
#version 450
layout(vertices=3) out;
void main(){
gl_TessLevelOuter[0] = gl_TessLevelOuter[1] = gl_TessLevelOuter[2] = 1;
gl_TessLevelInner[0] = 1;
}
)glsl";
char const *tesSource = R"glsl(
#version 450
layout(triangles, equal_spacing, cw) in;
void main(){
gl_Position.xyz = gl_TessCoord;
gl_Position.w = 1.0f;
}
)glsl";
VkShaderObj tcs(this, tcsSource, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
VkShaderObj tes(this, tesSource, VK_SHADER_STAGE_TESSELLATION_EVALUATION_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_.renderPass = render_pass.handle();
pipe.gp_ci_.subpass = 0;
pipe.cb_ci_.attachmentCount = 1;
pipe.gp_ci_.pTessellationState = &tsci;
pipe.gp_ci_.pInputAssemblyState = &iasci;
pipe.shader_stages_.emplace_back(tcs.GetStageCreateInfo());
pipe.shader_stages_.emplace_back(tes.GetStageCreateInfo());
pipe.InitState();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06047");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
if (features2.features.geometryShader) {
static char const *gsSource = R"glsl(
#version 450
layout (points) in;
layout (triangle_strip) out;
layout (max_vertices = 3) out;
void main() {
gl_Position = vec4(1.0, 0.5, 0.5, 0.0);
EmitVertex();
}
)glsl";
VkShaderObj vs(this, kVertexPointSizeGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj gs(this, gsSource, VK_SHADER_STAGE_GEOMETRY_BIT);
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.renderPass = render_pass.handle();
pipe.gp_ci_.subpass = 0;
pipe.cb_ci_.attachmentCount = 1;
pipe.shader_stages_ = {vs.GetStageCreateInfo(), gs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()};
pipe.ia_ci_.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
pipe.InitState();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06048");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeMultiview, DynamicRenderingMaxMultiviewInstanceIndex) {
TEST_DESCRIPTION("Draw with multiview enabled and instance index too high.");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-maxMultiviewInstanceIndex-02688");
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
SetTargetApiVersion(VK_API_VERSION_1_2);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamic_rendering_features = vku::InitStructHelper();
VkPhysicalDeviceVulkan11Features features11 = vku::InitStructHelper(&dynamic_rendering_features);
GetPhysicalDeviceFeatures2(features11);
if (!features11.multiview) {
GTEST_SKIP() << "multiview not supported.";
}
RETURN_IF_SKIP(InitState(nullptr, &features11));
VkPhysicalDeviceMultiviewProperties multiview_properties = vku::InitStructHelper();
GetPhysicalDeviceProperties2(multiview_properties);
VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM;
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.viewMask = 0x1;
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_format;
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.gp_ci_.pNext = &pipeline_rendering_info;
pipe.CreateGraphicsPipeline();
VkImageObj img(m_device);
img.Init(m_width, m_height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL);
VkImageView view = img.targetView(VK_FORMAT_R8G8B8A8_UNORM);
VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper();
color_attachment.imageView = view;
color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
VkRenderingInfoKHR renderingInfo = vku::InitStructHelper();
renderingInfo.renderArea = {{0, 0}, {100u, 100u}};
renderingInfo.layerCount = 1u;
renderingInfo.colorAttachmentCount = 1u;
renderingInfo.pColorAttachments = &color_attachment;
renderingInfo.viewMask = 0x1;
m_commandBuffer->begin();
m_commandBuffer->BeginRendering(renderingInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
vk::CmdDraw(m_commandBuffer->handle(), 3u, 1u, 0u, multiview_properties.maxMultiviewInstanceIndex);
m_commandBuffer->EndRendering();
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
}