blob: 4efb7646095b089f0b7a7a472cd34e352d41be28 [file] [log] [blame]
/*
* Copyright (c) 2015-2025 The Khronos Group Inc.
* Copyright (c) 2015-2025 Valve Corporation
* Copyright (c) 2015-2025 LunarG, Inc.
* Copyright (c) 2015-2025 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include <vulkan/vulkan_core.h>
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
#include "../framework/render_pass_helper.h"
class PositiveMultiview : public VkLayerTest {};
TEST_F(PositiveMultiview, RenderPassQueries) {
TEST_DESCRIPTION("Use queries in a render pass instance with multiview enabled.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::multiview);
RETURN_IF_SKIP(Init());
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddColorAttachment(0);
uint32_t view_masks[] = {0x3u};
uint32_t correlation_masks[] = {0x1u};
VkRenderPassMultiviewCreateInfo rpmvci = vku::InitStructHelper();
rpmvci.subpassCount = 1;
rpmvci.pViewMasks = view_masks;
rpmvci.correlationMaskCount = 1;
rpmvci.pCorrelationMasks = correlation_masks;
rp.CreateRenderPass(&rpmvci);
auto image_ci = vkt::Image::ImageCreateInfo2D(32, 32, 2, 3, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::Image image(*m_device, image_ci, vkt::set_layout);
vkt::ImageView view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY, 0, 1, 0, 3);
vkt::Framebuffer fb(*m_device, rp, 1, &view.handle());
vkt::Buffer buffer(*m_device, 256, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vkt::QueryPool query_pool(*m_device, VK_QUERY_TYPE_OCCLUSION, 2);
m_command_buffer.Begin();
vk::CmdResetQueryPool(m_command_buffer, query_pool, 0, 2);
m_command_buffer.BeginRenderPass(rp, fb, 32, 32);
vk::CmdBeginQuery(m_command_buffer, query_pool, 0, 0);
vk::CmdEndQuery(m_command_buffer, query_pool, 0);
m_command_buffer.EndRenderPass();
vk::CmdCopyQueryPoolResults(m_command_buffer, query_pool, 0, 2, buffer, 0, 4, 0);
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
}
TEST_F(PositiveMultiview, BasicRenderPass) {
TEST_DESCRIPTION("Create render pass with view mask, with multiview feature enabled in Vulkan11Features.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::multiview);
RETURN_IF_SKIP(Init());
VkAttachmentDescription2 attach_desc = vku::InitStructHelper();
attach_desc.format = VK_FORMAT_R8G8B8A8_UNORM;
attach_desc.samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkSubpassDescription2 subpass = vku::InitStructHelper();
subpass.viewMask = 0x1;
VkRenderPassCreateInfo2 render_pass_ci = vku::InitStructHelper();
render_pass_ci.subpassCount = 1;
render_pass_ci.pSubpasses = &subpass;
render_pass_ci.attachmentCount = 1;
render_pass_ci.pAttachments = &attach_desc;
vkt::RenderPass render_pass(*m_device, render_pass_ci);
}
TEST_F(PositiveMultiview, PushDescriptor) {
TEST_DESCRIPTION("Begin render pass with view mask and a push descriptor.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::multiview);
RETURN_IF_SKIP(Init());
VkAttachmentDescription2 attach_desc = vku::InitStructHelper();
attach_desc.format = VK_FORMAT_R8G8B8A8_UNORM;
attach_desc.samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
std::array subpasses = {vku::InitStruct<VkSubpassDescription2>(), vku::InitStruct<VkSubpassDescription2>()};
subpasses[0].viewMask = 0x1;
subpasses[1].viewMask = 0x1;
VkRenderPassCreateInfo2 render_pass_ci = vku::InitStructHelper();
render_pass_ci.subpassCount = subpasses.size();
render_pass_ci.pSubpasses = subpasses.data();
render_pass_ci.attachmentCount = 1;
render_pass_ci.pAttachments = &attach_desc;
vkt::RenderPass render_pass(*m_device, render_pass_ci);
// A compatible framebuffer.
vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView view = image.CreateView();
vkt::Framebuffer fb(*m_device, render_pass, 1, &view.handle());
VkDescriptorSetLayoutBinding dsl_binding = {2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
const vkt::DescriptorSetLayout ds_layout(*m_device, {dsl_binding});
// Create push descriptor set layout
const vkt::DescriptorSetLayout push_ds_layout(*m_device, {dsl_binding}, VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT);
// Use helper to create graphics pipeline
CreatePipelineHelper pipe(*this);
pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&push_ds_layout, &ds_layout});
pipe.gp_ci_.renderPass = render_pass;
pipe.CreateGraphicsPipeline();
const uint32_t data_size = sizeof(float) * 3;
vkt::Buffer vbo(*m_device, data_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
VkDescriptorBufferInfo buff_info = {vbo, 0, data_size};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstBinding = 2;
descriptor_write.descriptorCount = 1;
descriptor_write.pTexelBufferView = nullptr;
descriptor_write.pBufferInfo = &buff_info;
descriptor_write.pImageInfo = nullptr;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.dstSet = 0; // Should not cause a validation error
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdPushDescriptorSetKHR(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1, &descriptor_write);
m_command_buffer.BeginRenderPass(render_pass, fb, 32, 32);
m_command_buffer.NextSubpass();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveMultiview, 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;
// Leave out the Layer builtin
perprimitiveEXT out gl_MeshPerPrimitiveEXT {
int gl_PrimitiveID;
int gl_ViewportIndex;
bool gl_CullPrimitiveEXT;
int gl_PrimitiveShadingRateEXT;
} gl_MeshPrimitivesEXT[];
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;
pipe.CreateGraphicsPipeline();
}