| /* |
| * 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. |
| * 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 <vulkan/vulkan_core.h> |
| #include "../framework/layer_validation_tests.h" |
| #include "../framework/pipeline_helper.h" |
| #include "../framework/descriptor_helper.h" |
| #include "../framework/render_pass_helper.h" |
| #include "binding.h" |
| #include "utils/convert_utils.h" |
| |
| class NegativeMultiview : public VkLayerTest {}; |
| |
| 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); |
| AddRequiredFeature(vkt::Feature::multiview); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMultiviewProperties multiview_props = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(multiview_props); |
| if (multiview_props.maxMultiviewInstanceIndex == vvl::kU32Max) { |
| GTEST_SKIP() << "maxMultiviewInstanceIndex is uint32_t max"; |
| } |
| |
| uint32_t viewMask = 0x1u; |
| VkRenderPassMultiviewCreateInfo renderPassMultiviewCreateInfo = vku::InitStructHelper(); |
| renderPassMultiviewCreateInfo.subpassCount = 1; |
| renderPassMultiviewCreateInfo.pViewMasks = &viewMask; |
| |
| RenderPassSingleSubpass rp(*this); |
| rp.AddAttachmentDescription(VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED); |
| rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL}); |
| rp.AddColorAttachment(0); |
| rp.CreateRenderPass(&renderPassMultiviewCreateInfo); |
| |
| VkImageCreateInfo image_create_info = vku::InitStructHelper(); |
| image_create_info.flags = 0u; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM; |
| image_create_info.extent = {32u, 32u, 1u}; |
| image_create_info.mipLevels = 1u; |
| image_create_info.arrayLayers = 2u; |
| 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; |
| vkt::Image image(*m_device, image_create_info, vkt::set_layout); |
| vkt::ImageView imageView = image.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY); |
| |
| vkt::Framebuffer framebuffer(*m_device, rp, 1, &imageView.handle()); |
| |
| VkRenderPassBeginInfo render_pass_bi = vku::InitStructHelper(); |
| render_pass_bi.renderPass = rp; |
| render_pass_bi.framebuffer = framebuffer; |
| render_pass_bi.renderArea.extent = {32u, 32u}; |
| render_pass_bi.clearValueCount = 1u; |
| render_pass_bi.pClearValues = m_renderPassClearValues.data(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.renderPass = rp; |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(render_pass_bi); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-maxMultiviewInstanceIndex-02688"); |
| vk::CmdDraw(m_command_buffer, 1, multiview_props.maxMultiviewInstanceIndex + 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeMultiview, ClearColorAttachments) { |
| TEST_DESCRIPTION("Test cmdClearAttachments with active render pass that uses multiview"); |
| |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiview); |
| RETURN_IF_SKIP(Init()); |
| |
| uint32_t viewMask = 0x1u; |
| VkRenderPassMultiviewCreateInfo renderPassMultiviewCreateInfo = vku::InitStructHelper(); |
| renderPassMultiviewCreateInfo.subpassCount = 1; |
| renderPassMultiviewCreateInfo.pViewMasks = &viewMask; |
| |
| RenderPassSingleSubpass rp(*this); |
| rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED); |
| rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL}); |
| rp.AddColorAttachment(0); |
| rp.CreateRenderPass(&renderPassMultiviewCreateInfo); |
| |
| 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 = {32, 32, 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; |
| vkt::Image image(*m_device, image_create_info, vkt::set_layout); |
| vkt::ImageView imageView = image.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY); |
| |
| vkt::Framebuffer framebuffer(*m_device, rp, 1, &imageView.handle()); |
| |
| // Start no RenderPass |
| m_command_buffer.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 = {32, 32}; |
| |
| m_command_buffer.BeginRenderPass(rp, framebuffer, 32, 32); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdClearAttachments-baseArrayLayer-00018"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdClearAttachments-pRects-06937"); |
| clear_rect.layerCount = 2; |
| vk::CmdClearAttachments(m_command_buffer, 1, &color_attachment, 1, &clear_rect); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdClearAttachments-baseArrayLayer-00018"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdClearAttachments-pRects-06937"); |
| clear_rect.baseArrayLayer = 1; |
| clear_rect.layerCount = 1; |
| vk::CmdClearAttachments(m_command_buffer, 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); |
| AddRequiredFeature(vkt::Feature::multiview); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| 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; |
| |
| std::vector<VkSubpassDescription> subpasses; |
| subpasses.resize(multiview_count); |
| for (unsigned i = 0; i < multiview_count; ++i) { |
| subpasses[i].colorAttachmentCount = 1; |
| 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; |
| |
| VkRenderPassCreateInfo rp_info = vku::InitStructHelper(&renderPassMultiviewCreateInfo); |
| rp_info.attachmentCount = 1; |
| rp_info.pAttachments = &attachmentDescription; |
| rp_info.subpassCount = subpasses.size(); |
| rp_info.pSubpasses = subpasses.data(); |
| |
| std::vector<VkSubpassDependency> dependencies; |
| dependencies.resize(extra_subpass_count); |
| for (unsigned i = 0; i < dependencies.size(); ++i) { |
| auto &subpass_dep = 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; |
| } |
| |
| rp_info.dependencyCount = static_cast<uint32_t>(dependencies.size()); |
| rp_info.pDependencies = dependencies.data(); |
| |
| vk::CreateRenderPass(*m_device, &rp_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 = {m_width, m_height, 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; |
| vkt::Image image(*m_device, image_create_info); |
| vkt::ImageView imageView = image.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY); |
| |
| vkt::Framebuffer fb(*m_device, m_renderPass, 1, &imageView.handle(), m_width, m_height); |
| |
| VkClearValue clear{}; |
| clear.color = m_clear_color; |
| m_renderPassClearValues.emplace_back(clear); |
| m_renderPassBeginInfo.renderPass = m_renderPass; |
| m_renderPassBeginInfo.framebuffer = fb; |
| m_renderPassBeginInfo.renderArea.extent = {m_width, 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.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| // This bind should not be valid after we begin the renderpass |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08606"); |
| vk::CmdDraw(m_command_buffer, 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_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| m_command_buffer.NextSubpass(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08606"); |
| vk::CmdDraw(m_command_buffer, 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| m_command_buffer.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.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_command_buffer.Begin(); |
| // This line width set should not be valid for next subpass |
| vk::CmdSetLineWidth(m_command_buffer, 1.0f); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08617"); |
| vk::CmdDraw(m_command_buffer, 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_command_buffer, 1.0f); |
| m_command_buffer.NextSubpass(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[i]); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08617"); |
| vk::CmdDraw(m_command_buffer, 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| m_command_buffer.Reset(); |
| |
| // Push constants |
| { |
| const char *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(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj const fs(*m_device, 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.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_command_buffer.Begin(); |
| // This push constants should not be counted when render pass begins |
| vk::CmdPushConstants(m_command_buffer, layout, VK_SHADER_STAGE_VERTEX_BIT, push_constant_range.offset, |
| push_constant_range.size, dummy_values); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-maintenance4-08602"); |
| vk::CmdDraw(m_command_buffer, 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_command_buffer, layout, VK_SHADER_STAGE_VERTEX_BIT, push_constant_range.offset, |
| push_constant_range.size, dummy_values); |
| m_command_buffer.NextSubpass(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[i]); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-maintenance4-08602"); |
| vk::CmdDraw(m_command_buffer, 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| m_command_buffer.Reset(); |
| |
| // Descriptor sets |
| { |
| vkt::Buffer buffer(*m_device, 8, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| OneOffDescriptorSet descriptor_set{m_device, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}}}; |
| descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| 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(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj const fs(*m_device, kFragmentUniformGlsl, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.pipeline_layout_ci_ = pipeline_layout_info; |
| 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_command_buffer.Begin(); |
| // This descriptor bind should not be counted when render pass begins |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1, |
| &descriptor_set.set_, 0, nullptr); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08600"); |
| vk::CmdDraw(m_command_buffer, 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_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1, |
| &descriptor_set.set_, 0, nullptr); |
| m_command_buffer.NextSubpass(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[i]); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08600"); |
| vk::CmdDraw(m_command_buffer, 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| m_command_buffer.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; |
| |
| const char *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(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj fs(*m_device, 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.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_command_buffer.Begin(); |
| // This vertex buffer bind should not be counted when render pass begins |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vbo.handle(), &offset); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-04007"); |
| vk::CmdDraw(m_command_buffer, 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_command_buffer, 0, 1, &vbo.handle(), &offset); |
| m_command_buffer.NextSubpass(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[i]); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-04007"); |
| vk::CmdDraw(m_command_buffer, 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| m_command_buffer.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; |
| |
| const char *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(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj fs(*m_device, 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.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_command_buffer.Begin(); |
| // This index buffer bind should not be counted when render pass begins |
| vk::CmdBindIndexBuffer(m_command_buffer, ibo, 0, VK_INDEX_TYPE_UINT32); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vbo.handle(), &offset); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawIndexed-None-07312"); |
| vk::CmdDrawIndexed(m_command_buffer, 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_command_buffer, ibo, 0, VK_INDEX_TYPE_UINT32); |
| m_command_buffer.NextSubpass(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[i]); |
| vk::CmdBindVertexBuffers(m_command_buffer, 0, 1, &vbo.handle(), &offset); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawIndexed-None-07312"); |
| vk::CmdDrawIndexed(m_command_buffer, 0, 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.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); |
| AddRequiredFeature(vkt::Feature::transformFeedback); |
| AddRequiredFeature(vkt::Feature::multiview); |
| RETURN_IF_SKIP(Init()); |
| |
| uint32_t viewMask = 0x1u; |
| VkRenderPassMultiviewCreateInfo renderPassMultiviewCreateInfo = vku::InitStructHelper(); |
| renderPassMultiviewCreateInfo.subpassCount = 1; |
| renderPassMultiviewCreateInfo.pViewMasks = &viewMask; |
| |
| RenderPassSingleSubpass rp(*this); |
| rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED); |
| rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL}); |
| rp.AddColorAttachment(0); |
| rp.CreateRenderPass(&renderPassMultiviewCreateInfo); |
| |
| 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 = {32, 32, 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; |
| vkt::Image image(*m_device, image_create_info, vkt::set_layout); |
| auto image_view_ci = image.BasicViewCreatInfo(); |
| image_view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; |
| const vkt::ImageView imageView(*m_device, image_view_ci); |
| |
| vkt::Framebuffer framebuffer(*m_device, rp, 1, &imageView.handle()); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.renderPass = rp; |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(rp, framebuffer, 32, 32); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| vkt::Buffer buffer(*m_device, 16, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT); |
| VkDeviceSize offset = 0; |
| vk::CmdBindTransformFeedbackBuffersEXT(m_command_buffer, 0, 1, &buffer.handle(), &offset, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBeginTransformFeedbackEXT-None-04128"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdBeginTransformFeedbackEXT-None-02373"); |
| vk::CmdBeginTransformFeedbackEXT(m_command_buffer, 0, 1, nullptr, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeMultiview, Features) { |
| TEST_DESCRIPTION("Checks VK_KHR_multiview features."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitFramework()); |
| std::vector<const char *> extension_list; |
| if (DeviceValidationVersion() < VK_API_VERSION_1_1) { |
| extension_list.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 = extension_list.data(); |
| device_create_info.enabledExtensionCount = extension_list.size(); |
| VkDevice test_device; |
| |
| 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->SetDesiredError("VUID-VkPhysicalDeviceMultiviewFeatures-multiviewGeometryShader-00580"); |
| } |
| if (multiview_features.multiviewTessellationShader == VK_TRUE) { |
| m_errorMonitor->SetDesiredError("VUID-VkPhysicalDeviceMultiviewFeatures-multiviewTessellationShader-00581"); |
| } |
| vk::CreateDevice(Gpu(), &device_create_info, nullptr, &test_device); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMultiview, RenderPassCreateOverlappingCorrelationMasks) { |
| TEST_DESCRIPTION("Create a subpass with overlapping correlation masks"); |
| |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| AddOptionalExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiview); |
| RETURN_IF_SKIP(Init()); |
| const bool rp2Supported = IsExtensionsEnabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); |
| |
| 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); |
| |
| // Correlation masks must not overlap |
| correlationMasks[1] = 0x3u; |
| CreateRenderPassTest(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; |
| auto safe_rpci2 = ConvertVkRenderPassCreateInfoToV2KHR(rpci); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkRenderPassCreateInfo2-viewMask-03057"); |
| vkt::RenderPass rp2(*m_device, *safe_rpci2.ptr()); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| 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_MULTIVIEW_EXTENSION_NAME); |
| AddOptionalExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiview); |
| RETURN_IF_SKIP(Init()); |
| const bool rp2Supported = IsExtensionsEnabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); |
| |
| 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 |
| CreateRenderPassTest(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_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| AddOptionalExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); |
| RETURN_IF_SKIP(Init()); |
| const bool rp2Supported = IsExtensionsEnabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); |
| |
| 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); |
| |
| CreateRenderPassTest(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_MULTIVIEW_EXTENSION_NAME); |
| AddOptionalExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiViewport); |
| AddRequiredFeature(vkt::Feature::multiview); |
| RETURN_IF_SKIP(Init()); |
| const bool rp2Supported = IsExtensionsEnabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); |
| |
| 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); |
| subpass2.viewMask = 0x0u; |
| rpci2.pSubpasses = &subpass2; |
| rp2[1].Init(*m_device, rpci2); |
| subpass2.viewMask = 0x1u; |
| rpci2.pSubpasses = &subpass2; |
| rp2[2].Init(*m_device, rpci2); |
| } |
| |
| auto ici2d = vkt::Image::ImageCreateInfo2D(128, 128, 1, 2, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| vkt::Image image(*m_device, ici2d); |
| vkt::ImageView iv = image.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY, 0, 1, 0, 2); |
| |
| // Create framebuffers for rp[0] and rp2[0] |
| VkFramebufferCreateInfo fbci = vku::InitStructHelper(); |
| fbci.renderPass = rp[0]; |
| 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]; |
| fb2.Init(*m_device, fbci); |
| } |
| |
| VkRenderPassBeginInfo rp_begin = vku::InitStructHelper(); |
| rp_begin.renderPass = rp[0]; |
| rp_begin.framebuffer = fb; |
| rp_begin.renderArea = {{0, 0}, {128, 128}}; |
| |
| // Create a graphics pipeline with rp[1] |
| CreatePipelineHelper pipe_1(*this); |
| pipe_1.gp_ci_.layout = pipeline_layout; |
| pipe_1.gp_ci_.renderPass = rp[1]; |
| pipe_1.CreateGraphicsPipeline(); |
| |
| // Create a graphics pipeline with rp[2] |
| CreatePipelineHelper pipe_2(*this); |
| pipe_2.gp_ci_.layout = pipeline_layout; |
| pipe_2.gp_ci_.renderPass = rp[2]; |
| pipe_2.CreateGraphicsPipeline(); |
| |
| CreatePipelineHelper pipe2_1(*this); |
| CreatePipelineHelper pipe2_2(*this); |
| if (rp2Supported) { |
| pipe2_1.gp_ci_.layout = pipeline_layout; |
| pipe2_1.gp_ci_.renderPass = rp[1]; |
| pipe2_1.CreateGraphicsPipeline(); |
| |
| pipe2_2.gp_ci_.layout = pipeline_layout; |
| pipe2_2.gp_ci_.renderPass = rp[2]; |
| pipe2_2.CreateGraphicsPipeline(); |
| } |
| |
| VkCommandBufferInheritanceInfo cbii = vku::InitStructHelper(); |
| cbii.renderPass = rp[0]; |
| cbii.subpass = 0; |
| VkCommandBufferBeginInfo cbbi = vku::InitStructHelper(); |
| cbbi.pInheritanceInfo = &cbii; |
| |
| // Begin rp[0] for VK_VERSION_1_0 test cases |
| vk::BeginCommandBuffer(m_command_buffer, &cbbi); |
| vk::CmdBeginRenderPass(m_command_buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); |
| |
| // Bind rp[1]'s pipeline to command buffer |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_1); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-renderPass-02684"); |
| // Render triangle (error on Multiview usage should trigger on draw) |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Bind rp[2]'s pipeline to command buffer |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_2); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-renderPass-02684"); |
| // Render triangle (error on non-matching viewMasks for Multiview usage should trigger on draw) |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // End rp[0] |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| // Begin rp2[0] for VK_VERSION_1_2 test cases |
| if (rp2Supported) { |
| cbii.renderPass = rp2[0]; |
| rp_begin.renderPass = rp2[0]; |
| rp_begin.framebuffer = fb2; |
| vk::BeginCommandBuffer(m_command_buffer, &cbbi); |
| vk::CmdBeginRenderPass(m_command_buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); |
| |
| // Bind rp2[1]'s pipeline to command buffer |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2_1); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-renderPass-02684"); |
| // Render triangle (error on Multiview usage should trigger on draw) |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // Bind rp2[2]'s pipeline to command buffer |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2_2); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-renderPass-02684"); |
| // Render triangle (error on non-matching viewMasks for Multiview usage should trigger on draw) |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // End rp2[0] |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| } |
| |
| TEST_F(NegativeMultiview, RenderPassViewMasksZero) { |
| TEST_DESCRIPTION("Create a render pass with some view masks 0 and some not 0"); |
| |
| AddRequiredExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiview); |
| RETURN_IF_SKIP(Init()); |
| |
| 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); |
| |
| CreateRenderPassTest(rpci, false, "VUID-VkRenderPassCreateInfo-pNext-02513", nullptr); |
| } |
| |
| TEST_F(NegativeMultiview, RenderPassViewOffsets) { |
| TEST_DESCRIPTION("Create a render pass with invalid multiview pViewOffsets"); |
| |
| AddRequiredExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiview); |
| RETURN_IF_SKIP(Init()); |
| |
| 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); |
| |
| CreateRenderPassTest(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); |
| AddRequiredFeature(vkt::Feature::multiview); |
| RETURN_IF_SKIP(Init()); |
| |
| 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); |
| |
| CreateRenderPassTest(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); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::tessellationShader); |
| AddRequiredFeature(vkt::Feature::geometryShader); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| RenderPass2SingleSubpass rp(*this); |
| rp.AddAttachmentDescription(VK_FORMAT_B8G8R8A8_UNORM); |
| rp.AddAttachmentReference(0, VK_IMAGE_LAYOUT_GENERAL); |
| rp.AddColorAttachment(0); |
| rp.SetViewMask(0x3u); |
| rp.CreateRenderPass(); |
| |
| // tessellationShader |
| { |
| const char *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"; |
| const char *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(*m_device, tcsSource, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); |
| VkShaderObj tes(*m_device, 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 = rp; |
| 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()); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkGraphicsPipelineCreateInfo-renderPass-06047"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| // geometryShader |
| { |
| const char *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(*m_device, kVertexPointSizeGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj gs(*m_device, gsSource, VK_SHADER_STAGE_GEOMETRY_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.renderPass = rp; |
| 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; |
| |
| m_errorMonitor->SetDesiredError("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->SetDesiredError("VUID-vkCmdDraw-maxMultiviewInstanceIndex-02688"); |
| |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::multiview); |
| RETURN_IF_SKIP(Init()); |
| |
| 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, &pipeline_rendering_info); |
| pipe.CreateGraphicsPipeline(); |
| |
| vkt::Image img(*m_device, m_width, m_height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| vkt::ImageView view = img.CreateView(); |
| |
| 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; |
| |
| VkRenderingInfo renderingInfo = vku::InitStructHelper(); |
| renderingInfo.renderArea = {{0, 0}, {100u, 100u}}; |
| renderingInfo.layerCount = 1u; |
| renderingInfo.colorAttachmentCount = 1u; |
| renderingInfo.pColorAttachments = &color_attachment; |
| renderingInfo.viewMask = 0x1; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRendering(renderingInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdDraw(m_command_buffer, 3u, 1u, 0u, multiview_properties.maxMultiviewInstanceIndex); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMultiview, ShaderLayerBuiltInRenderPass) { |
| TEST_DESCRIPTION("Create invalid pipeline that writes to Layer built-in"); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::geometryShader); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::multiviewGeometryShader); |
| RETURN_IF_SKIP(Init()); |
| |
| const char *gsSource = R"glsl( |
| #version 450 |
| layout (triangles) in; |
| layout (triangle_strip) out; |
| layout (max_vertices = 1) out; |
| void main() { |
| gl_Position = vec4(1.0, 0.5, 0.5, 0.0); |
| EmitVertex(); |
| gl_Layer = 4; |
| } |
| )glsl"; |
| |
| VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj gs(*m_device, gsSource, VK_SHADER_STAGE_GEOMETRY_BIT); |
| |
| VkAttachmentReference color_att = {}; |
| color_att.layout = VK_IMAGE_LAYOUT_GENERAL; |
| |
| VkAttachmentDescription attach = {}; |
| attach.samples = VK_SAMPLE_COUNT_1_BIT; |
| attach.format = VK_FORMAT_R8G8B8A8_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 view_masks[] = {0x3u}; |
| VkRenderPassMultiviewCreateInfo rpmvci = vku::InitStructHelper(); |
| rpmvci.subpassCount = 1; |
| rpmvci.pViewMasks = view_masks; |
| |
| VkRenderPassCreateInfo rpci = vku::InitStructHelper(&rpmvci); |
| rpci.attachmentCount = 1; |
| rpci.pAttachments = &attach; |
| rpci.subpassCount = 1; |
| rpci.pSubpasses = &subpass; |
| vkt::RenderPass render_pass(*m_device, rpci); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), gs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.gp_ci_.renderPass = render_pass; |
| m_errorMonitor->SetDesiredError("VUID-VkGraphicsPipelineCreateInfo-renderPass-06050"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMultiview, ShaderLayerBuiltInDynamicRendering) { |
| TEST_DESCRIPTION("Create invalid pipeline that writes to Layer built-in"); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::geometryShader); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::multiviewGeometryShader); |
| RETURN_IF_SKIP(Init()); |
| |
| const char *gsSource = R"glsl( |
| #version 450 |
| layout (triangles) in; |
| layout (triangle_strip) out; |
| layout (max_vertices = 1) out; |
| void main() { |
| gl_Position = vec4(1.0, 0.5, 0.5, 0.0); |
| EmitVertex(); |
| gl_Layer = 4; |
| } |
| )glsl"; |
| |
| VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj gs(*m_device, gsSource, VK_SHADER_STAGE_GEOMETRY_BIT); |
| |
| VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM; |
| |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| pipeline_rendering_info.colorAttachmentCount = 1; |
| pipeline_rendering_info.pColorAttachmentFormats = &color_format; |
| pipeline_rendering_info.viewMask = 0x1; |
| |
| CreatePipelineHelper pipe(*this, &pipeline_rendering_info); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), gs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.gp_ci_.renderPass = VK_NULL_HANDLE; |
| m_errorMonitor->SetDesiredError("VUID-VkGraphicsPipelineCreateInfo-renderPass-06059"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMultiview, MultiviewPerViewRenderAreasFeature) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredExtensions(VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| RETURN_IF_SKIP(Init()); |
| |
| vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| vkt::ImageView image_view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageView = image_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; |
| |
| VkRect2D view_render_area = {{0, 0}, {32, 32}}; |
| VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM multiview_pre_view = vku::InitStructHelper(); |
| multiview_pre_view.perViewRenderAreaCount = 1; |
| multiview_pre_view.pPerViewRenderAreas = &view_render_area; |
| |
| VkRenderingInfo rendering_info = vku::InitStructHelper(&multiview_pre_view); |
| rendering_info.renderArea = {{0, 0}, {32, 32}}; |
| rendering_info.layerCount = 1u; |
| rendering_info.colorAttachmentCount = 1u; |
| rendering_info.pColorAttachments = &color_attachment; |
| rendering_info.viewMask = 0x1; |
| |
| m_command_buffer.Begin(); |
| m_errorMonitor->SetDesiredError("VUID-VkRenderingInfo-perViewRenderAreaCount-07857"); |
| m_command_buffer.BeginRendering(rendering_info); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeMultiview, MultiviewPerViewRenderAreas) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredExtensions(VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::multiviewPerViewRenderAreas); |
| RETURN_IF_SKIP(Init()); |
| |
| vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| vkt::ImageView image_view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageView = image_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; |
| |
| VkRect2D view_render_area[2] = {{{-1, 0}, {16, 16}}, {{0, -1}, {16, 16}}}; |
| VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM multiview_pre_view = vku::InitStructHelper(); |
| multiview_pre_view.perViewRenderAreaCount = 2; |
| multiview_pre_view.perViewRenderAreaCount = 2; |
| multiview_pre_view.pPerViewRenderAreas = view_render_area; |
| |
| VkRenderingInfo rendering_info = vku::InitStructHelper(&multiview_pre_view); |
| rendering_info.renderArea = {{-1, -1}, {31, 31}}; |
| rendering_info.layerCount = 1u; |
| rendering_info.colorAttachmentCount = 1u; |
| rendering_info.pColorAttachments = &color_attachment; |
| rendering_info.viewMask = 0x3; |
| |
| m_command_buffer.Begin(); |
| m_errorMonitor->SetDesiredError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07861"); |
| m_errorMonitor->SetDesiredError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-offset-07862"); |
| m_command_buffer.BeginRendering(rendering_info); |
| m_errorMonitor->VerifyFound(); |
| |
| view_render_area[0] = {{0, 0}, {16, 16}}; |
| view_render_area[1] = {{0, 0}, {32, 16}}; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkRenderingInfo-perViewRenderAreaCount-07858"); |
| m_command_buffer.BeginRendering(rendering_info); |
| m_errorMonitor->VerifyFound(); |
| |
| multiview_pre_view.perViewRenderAreaCount = 1; |
| m_errorMonitor->SetDesiredError("VUID-VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM-pNext-07866"); |
| m_command_buffer.BeginRendering(rendering_info); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeMultiview, MeshShader) { |
| TEST_DESCRIPTION("https://gitlab.khronos.org/vulkan/vulkan/-/issues/4194"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::multiviewMeshShader); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| const char *mesh_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| layout(max_vertices=81) out; |
| layout(max_primitives=32) out; |
| layout(triangles) out; |
| |
| void main() { |
| SetMeshOutputsEXT(81, 32); |
| gl_MeshPrimitivesEXT[0].gl_CullPrimitiveEXT = true; |
| } |
| )glsl"; |
| |
| VkShaderObj ms(*m_device, mesh_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_2); |
| |
| VkAttachmentReference color_attachment = {0, VK_IMAGE_LAYOUT_GENERAL}; |
| |
| VkAttachmentDescription attach_desc = {}; |
| attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; |
| attach_desc.format = VK_FORMAT_R8G8B8A8_UNORM; |
| attach_desc.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL; |
| |
| VkSubpassDescription subpass = {}; |
| subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; |
| subpass.colorAttachmentCount = 1; |
| subpass.pColorAttachments = &color_attachment; |
| |
| uint32_t view_masks[] = {0x3u}; |
| VkRenderPassMultiviewCreateInfo rp_multiview_ci = vku::InitStructHelper(); |
| rp_multiview_ci.subpassCount = 1; |
| rp_multiview_ci.pViewMasks = view_masks; |
| |
| VkRenderPassCreateInfo rpci = vku::InitStructHelper(&rp_multiview_ci); |
| rpci.attachmentCount = 1; |
| rpci.pAttachments = &attach_desc; |
| rpci.subpassCount = 1; |
| rpci.pSubpasses = &subpass; |
| vkt::RenderPass render_pass(*m_device, rpci); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {ms.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.renderPass = render_pass; |
| m_errorMonitor->SetDesiredError("VUID-VkGraphicsPipelineCreateInfo-renderPass-06050"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMultiview, MultiviewPerViewViewports) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| AddRequiredExtensions(VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::multiviewPerViewViewports); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| uint32_t view_mask = 0x2u; |
| VkRenderPassMultiviewCreateInfo rp_mv_ci = vku::InitStructHelper(); |
| rp_mv_ci.subpassCount = 1; |
| rp_mv_ci.pViewMasks = &view_mask; |
| |
| RenderPassSingleSubpass rp(*this); |
| rp.AddAttachmentDescription(VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED); |
| rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL}); |
| rp.AddColorAttachment(0); |
| rp.CreateRenderPass(&rp_mv_ci); |
| |
| VkImageCreateInfo image_create_info = vku::InitStructHelper(); |
| image_create_info.flags = 0u; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM; |
| image_create_info.extent = {32u, 32u, 1u}; |
| image_create_info.mipLevels = 1u; |
| image_create_info.arrayLayers = 2u; |
| 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; |
| vkt::Image image(*m_device, image_create_info, vkt::set_layout); |
| vkt::ImageView image_view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY); |
| |
| vkt::Framebuffer framebuffer(*m_device, rp, 1, &image_view.handle()); |
| |
| VkRenderPassBeginInfo render_pass_bi = vku::InitStructHelper(); |
| render_pass_bi.renderPass = rp; |
| render_pass_bi.framebuffer = framebuffer; |
| render_pass_bi.renderArea.extent = {32u, 32u}; |
| render_pass_bi.clearValueCount = 1u; |
| render_pass_bi.pClearValues = m_renderPassClearValues.data(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.renderPass = rp; |
| m_errorMonitor->SetDesiredError("VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07730"); |
| m_errorMonitor->SetDesiredError("VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07731"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMultiview, MultiviewPerViewViewportsDynamicRendering) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| AddRequiredExtensions(VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::multiviewPerViewViewports); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| RETURN_IF_SKIP(Init()); |
| |
| VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM; |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| pipeline_rendering_info.viewMask = 0x2u; |
| pipeline_rendering_info.colorAttachmentCount = 1; |
| pipeline_rendering_info.pColorAttachmentFormats = &color_format; |
| |
| CreatePipelineHelper pipe(*this, &pipeline_rendering_info); |
| m_errorMonitor->SetDesiredError("VUID-VkGraphicsPipelineCreateInfo-multiviewPerViewViewports-12249"); |
| m_errorMonitor->SetDesiredError("VUID-VkGraphicsPipelineCreateInfo-multiviewPerViewViewports-12250"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMultiview, MultiviewPerViewViewportsDraw) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| AddRequiredExtensions(VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::multiviewPerViewViewports); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| RETURN_IF_SKIP(Init()); |
| |
| VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM; |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| pipeline_rendering_info.viewMask = 0x2u; |
| pipeline_rendering_info.colorAttachmentCount = 1; |
| pipeline_rendering_info.pColorAttachmentFormats = &color_format; |
| |
| CreatePipelineHelper pipe(*this, &pipeline_rendering_info); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT); |
| pipe.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT); |
| pipe.vp_state_ci_.viewportCount = 0u; |
| pipe.vp_state_ci_.scissorCount = 0u; |
| pipe.CreateGraphicsPipeline(); |
| |
| vkt::Image image(*m_device, m_width, m_height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| vkt::ImageView image_view = image.CreateView(); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageView = image_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; |
| |
| VkRenderingInfo rendering_info = vku::InitStructHelper(); |
| rendering_info.renderArea = {{0, 0}, {100u, 100u}}; |
| rendering_info.layerCount = 1u; |
| rendering_info.colorAttachmentCount = 1u; |
| rendering_info.pColorAttachments = &color_attachment; |
| rendering_info.viewMask = 0x2; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRendering(rendering_info); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| VkRect2D scissor[1] = {{{0, 0}, {1, 1}}}; |
| VkViewport viewport = {0, 0, 1, 1, 0.0f, 0.0f}; |
| vk::CmdSetScissorWithCountEXT(m_command_buffer, 1, scissor); |
| vk::CmdSetViewportWithCountEXT(m_command_buffer, 1, &viewport); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-multiviewPerViewViewports-12262"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-multiviewPerViewViewports-12263"); |
| vk::CmdDraw(m_command_buffer, 1, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |