blob: 46d33fb016e0e18cc97147aa38942f1417828b77 [file] [log] [blame]
/*
* Copyright (c) 2024-2025 Valve Corporation
* Copyright (c) 2024-2025 LunarG, 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/descriptor_helper.h"
#include "../framework/render_pass_helper.h"
class NegativeImageLayout : public ImageTest {};
TEST_F(NegativeImageLayout, Blit) {
TEST_DESCRIPTION("Incorrect vkCmdBlitImage layouts");
RETURN_IF_SKIP(Init());
VkFormat fmt = VK_FORMAT_R8G8B8A8_UNORM;
vkt::Image img_src_transfer(*m_device, 64, 64, fmt, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::Image img_dst_transfer(*m_device, 64, 64, fmt, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::Image img_general(*m_device, 64, 64, fmt, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::Image img_color(*m_device, 64, 64, fmt,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
img_src_transfer.SetLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
img_dst_transfer.SetLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
img_general.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
img_color.SetLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
VkImageBlit blit_region = {};
blit_region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
blit_region.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
blit_region.srcOffsets[0] = {0, 0, 0};
blit_region.srcOffsets[1] = {32, 32, 1};
blit_region.dstOffsets[0] = {32, 32, 0};
blit_region.dstOffsets[1] = {64, 64, 1};
// Illegal srcImageLayout/dstImageLayout
m_command_buffer.Begin();
vk::CmdBlitImage(m_command_buffer, img_general, VK_IMAGE_LAYOUT_GENERAL, img_general, VK_IMAGE_LAYOUT_GENERAL, 1, &blit_region,
VK_FILTER_LINEAR);
m_errorMonitor->SetDesiredError("VUID-vkCmdBlitImage-srcImageLayout-01398");
vk::CmdBlitImage(m_command_buffer, img_src_transfer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, img_dst_transfer,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit_region, VK_FILTER_LINEAR);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("VUID-vkCmdBlitImage-dstImageLayout-01399");
vk::CmdBlitImage(m_command_buffer, img_src_transfer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, img_dst_transfer,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1, &blit_region, VK_FILTER_LINEAR);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
// Destination image in invalid layout at start of the CB
m_command_buffer.Begin();
vk::CmdBlitImage(m_command_buffer, img_src_transfer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, img_color, VK_IMAGE_LAYOUT_GENERAL,
1, &blit_region, VK_FILTER_LINEAR);
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
// Source image in invalid layout at start of the CB
m_command_buffer.Begin();
vk::CmdBlitImage(m_command_buffer, img_color, VK_IMAGE_LAYOUT_GENERAL, img_dst_transfer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &blit_region, VK_FILTER_LINEAR);
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
// Source image in invalid layout in the middle of CB
VkImageMemoryBarrier img_barrier = vku::InitStructHelper();
img_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
img_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
img_barrier.image = img_general;
img_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
img_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr,
0, nullptr, 1, &img_barrier);
m_errorMonitor->SetDesiredError("VUID-vkCmdBlitImage-srcImageLayout-00221");
vk::CmdBlitImage(m_command_buffer, img_general, VK_IMAGE_LAYOUT_GENERAL, img_dst_transfer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &blit_region, VK_FILTER_LINEAR);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
// Destination image in invalid layout in the middle of CB
img_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
img_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
img_barrier.image = img_dst_transfer;
m_command_buffer.Begin();
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr,
0, nullptr, 1, &img_barrier);
m_errorMonitor->SetDesiredError("VUID-vkCmdBlitImage-dstImageLayout-00226");
vk::CmdBlitImage(m_command_buffer, img_src_transfer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, img_dst_transfer,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit_region, VK_FILTER_LINEAR);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeImageLayout, Compute) {
TEST_DESCRIPTION("Attempt to use an image with an invalid layout in a compute shader");
AddRequiredExtensions(VK_KHR_DEVICE_GROUP_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const char *cs = R"glsl(#version 450
layout(local_size_x=1) in;
layout(set=0, binding=0) uniform sampler2D s;
void main(){
vec4 v = 2.0 * texture(s, vec2(0.0));
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, cs, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr};
pipe.CreateComputePipeline();
const VkFormat fmt = VK_FORMAT_R8G8B8A8_UNORM;
vkt::Image image(*m_device, 64, 64, fmt, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
vkt::ImageView view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
pipe.descriptor_set_.WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
pipe.descriptor_set_.UpdateDescriptorSets();
{ // Verify invalid image layout with CmdDispatch
vkt::CommandBuffer cmd(*m_device, m_command_pool);
cmd.Begin();
vk::CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_, 0, 1, &pipe.descriptor_set_.set_, 0,
nullptr);
vk::CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdDispatch(cmd, 1, 1, 1);
cmd.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_default_queue->Submit(cmd);
m_default_queue->Wait();
m_errorMonitor->VerifyFound();
}
{ // Verify invalid image layout with CmdDispatchBaseKHR
vkt::CommandBuffer cmd(*m_device, m_command_pool);
cmd.Begin();
vk::CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_, 0, 1, &pipe.descriptor_set_.set_, 0,
nullptr);
vk::CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdDispatchBaseKHR(cmd, 0, 0, 0, 1, 1, 1);
cmd.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_default_queue->Submit(cmd);
m_default_queue->Wait();
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeImageLayout, Compute11) {
TEST_DESCRIPTION("Attempt to use an image with an invalid layout in a compute shader using vkCmdDispatchBase");
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(Init());
const char *cs = R"glsl(#version 450
layout(local_size_x=1) in;
layout(set=0, binding=0) uniform sampler2D s;
void main(){
vec4 v = 2.0 * texture(s, vec2(0.0));
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, cs, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr};
pipe.CreateComputePipeline();
const VkFormat fmt = VK_FORMAT_R8G8B8A8_UNORM;
vkt::Image image(*m_device, 64, 64, fmt, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
vkt::ImageView view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
pipe.descriptor_set_.WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
pipe.descriptor_set_.UpdateDescriptorSets();
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_, 0, 1,
&pipe.descriptor_set_.set_, 0, nullptr);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdDispatchBase(m_command_buffer, 0, 0, 0, 1, 1, 1);
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
// inspired by https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/5846
TEST_F(NegativeImageLayout, MultipleCommandDispatches) {
TEST_DESCRIPTION("Make sure we can detect the exact dispatch command that caused the error later");
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(Init());
const char *cs = R"glsl(
#version 450
layout(set=0, binding=0) uniform sampler2D s;
void main(){
vec4 v = texture(s, vec2(0.0));
}
)glsl";
OneOffDescriptorSet descriptor_set0(m_device,
{{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}});
OneOffDescriptorSet descriptor_set1(m_device,
{{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}});
vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set0.layout_});
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, cs, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr};
pipe.CreateComputePipeline();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
vkt::Image good_image(*m_device, 64, 64, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
good_image.SetLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkt::ImageView good_image_view = good_image.CreateView();
descriptor_set0.WriteDescriptorImageInfo(0, good_image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
descriptor_set0.UpdateDescriptorSets();
vkt::Image bad_image(*m_device, 64, 64, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
bad_image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
vkt::ImageView bad_image_view = bad_image.CreateView();
descriptor_set1.WriteDescriptorImageInfo(0, bad_image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
descriptor_set1.UpdateDescriptorSets();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
// contains good image
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set0.set_, 0,
nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
// contains bad image
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set1.set_, 0,
nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
// contains good image again
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set0.set_, 0,
nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8918
// This fails to create descriptor on RADV, might need to adjust OneOffDescriptorSet
TEST_F(NegativeImageLayout, DISABLED_Mutable) {
TEST_DESCRIPTION("Invalid image layout with mutable descriptors");
AddRequiredExtensions(VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::mutableDescriptorType);
RETURN_IF_SKIP(Init());
const char *cs = R"glsl(
#version 450
layout(set=0, binding=0) uniform sampler2D s;
void main(){
vec4 v = 2.0 * texture(s, vec2(0.0));
}
)glsl";
VkDescriptorType desc_types[2] = {
VK_DESCRIPTOR_TYPE_SAMPLER,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
};
VkMutableDescriptorTypeListEXT type_list = {2, desc_types};
VkMutableDescriptorTypeCreateInfoEXT mdtci = vku::InitStructHelper();
mdtci.mutableDescriptorTypeListCount = 1;
mdtci.pMutableDescriptorTypeLists = &type_list;
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_MUTABLE_EXT, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}}, 0,
&mdtci);
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, cs, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.cp_ci_.layout = pipeline_layout;
pipe.CreateComputePipeline();
const VkFormat fmt = VK_FORMAT_R8G8B8A8_UNORM;
vkt::Image image(*m_device, 64, 64, fmt, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
vkt::ImageView view = image.CreateView();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
descriptor_set.WriteDescriptorImageInfo(0, view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
descriptor_set.UpdateDescriptorSets();
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, PushDescriptor) {
TEST_DESCRIPTION("Use a push descriptor with a mismatched image layout.");
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const vkt::DescriptorSetLayout ds_layout(
*m_device, {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT);
auto pipeline_layout = vkt::PipelineLayout(*m_device, {&ds_layout});
const char *fsSource = R"glsl(
#version 450
layout(set=0, binding=0) uniform sampler2D tex;
layout(location=0) out vec4 color;
void main(){
color = textureLod(tex, vec2(0.5, 0.5), 0.0);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
pipe.CreateGraphicsPipeline();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
vkt::Image image(*m_device, 32, 32, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView image_view = image.CreateView();
image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
VkDescriptorImageInfo img_info = {sampler, image_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_write.pImageInfo = &img_info;
descriptor_write.dstArrayElement = 0;
descriptor_write.dstBinding = 0;
// Image layout is known at submit time
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdPushDescriptorSetKHR(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_write);
vk::CmdDraw(m_command_buffer, 1, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
// Image layout is known at record time
m_command_buffer.Begin();
image.ImageMemoryBarrier(m_command_buffer, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdPushDescriptorSetKHR(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_write);
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-imageLayout-00344");
vk::CmdDraw(m_command_buffer, 1, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
// INVALID_IMAGE_LAYOUT tests (one other case is hit by MapMemWithoutHostVisibleBit and not here)
TEST_F(NegativeImageLayout, Basic) {
TEST_DESCRIPTION("Generally these involve having images in the wrong layout when they're copied or transitioned.");
// 3 in ValidateCmdBufImageLayouts
// * -1 Attempt to submit cmd buf w/ deleted image
// * -2 Cmd buf submit of image w/ layout not matching first use w/ subresource
// * -3 Cmd buf submit of image w/ layout not matching first use w/o subresource
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
AddOptionalExtensions(VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
const bool copy_commands2 = IsExtensionsEnabled(VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME);
auto depth_format = FindSupportedDepthStencilFormat(Gpu());
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = VK_FORMAT_B8G8R8A8_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_TRANSFER_SRC_BIT;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_create_info.flags = 0;
vkt::Image src_image(*m_device, image_create_info, vkt::set_layout);
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
vkt::Image dst_image(*m_device, image_create_info, vkt::set_layout);
image_create_info.format = VK_FORMAT_D16_UNORM;
image_create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
vkt::Image depth_image(*m_device, image_create_info, vkt::set_layout);
m_command_buffer.Begin();
VkImageCopy copy_region;
copy_region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
copy_region.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
copy_region.srcOffset = {0, 0, 0};
copy_region.dstOffset = {0, 0, 0};
copy_region.extent = {1, 1, 1};
vk::CmdCopyImage(m_command_buffer, src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-srcImageLayout-01917");
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-srcImageLayout-00128");
vk::CmdCopyImage(m_command_buffer, src_image, VK_IMAGE_LAYOUT_UNDEFINED, dst_image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-dstImageLayout-00133");
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-dstImageLayout-01395");
vk::CmdCopyImage(m_command_buffer, src_image, VK_IMAGE_LAYOUT_GENERAL, dst_image, VK_IMAGE_LAYOUT_UNDEFINED, 1, &copy_region);
m_errorMonitor->VerifyFound();
// Equivalent tests using KHR_copy_commands2
if (copy_commands2) {
const VkImageCopy2 copy_region2 = {VK_STRUCTURE_TYPE_IMAGE_COPY_2,
NULL,
copy_region.srcSubresource,
copy_region.srcOffset,
copy_region.dstSubresource,
copy_region.dstOffset,
copy_region.extent};
VkCopyImageInfo2 copy_image_info2 = {VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2,
NULL,
src_image,
VK_IMAGE_LAYOUT_GENERAL,
dst_image,
VK_IMAGE_LAYOUT_GENERAL,
1,
&copy_region2};
m_command_buffer.FullMemoryBarrier();
vk::CmdCopyImage2KHR(m_command_buffer, &copy_image_info2);
m_errorMonitor->SetDesiredError("VUID-VkCopyImageInfo2-srcImageLayout-00128");
m_errorMonitor->SetDesiredError("VUID-VkCopyImageInfo2-srcImageLayout-01917");
copy_image_info2.srcImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
vk::CmdCopyImage2KHR(m_command_buffer, &copy_image_info2);
m_errorMonitor->VerifyFound();
// Now verify same checks for dst
copy_image_info2.srcImageLayout = VK_IMAGE_LAYOUT_GENERAL;
m_command_buffer.FullMemoryBarrier();
vk::CmdCopyImage2KHR(m_command_buffer, &copy_image_info2);
m_errorMonitor->SetDesiredError("VUID-VkCopyImageInfo2-dstImageLayout-00133");
m_errorMonitor->SetDesiredError("VUID-VkCopyImageInfo2-dstImageLayout-01395");
copy_image_info2.dstImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
vk::CmdCopyImage2KHR(m_command_buffer, &copy_image_info2);
m_errorMonitor->VerifyFound();
}
// Convert dst and depth images to TRANSFER_DST for subsequent tests
VkImageMemoryBarrier transfer_dst_image_barrier[1] = {};
transfer_dst_image_barrier[0] = vku::InitStructHelper();
transfer_dst_image_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
transfer_dst_image_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
transfer_dst_image_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
transfer_dst_image_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
transfer_dst_image_barrier[0].image = dst_image;
transfer_dst_image_barrier[0].subresourceRange.layerCount = image_create_info.arrayLayers;
transfer_dst_image_barrier[0].subresourceRange.levelCount = image_create_info.mipLevels;
transfer_dst_image_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 0,
NULL, 1, transfer_dst_image_barrier);
transfer_dst_image_barrier[0].image = depth_image;
transfer_dst_image_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 0,
NULL, 1, transfer_dst_image_barrier);
// Cause errors due to clearing with invalid image layouts
VkClearColorValue color_clear_value = {};
VkImageSubresourceRange clear_range;
clear_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clear_range.baseMipLevel = 0;
clear_range.baseArrayLayer = 0;
clear_range.layerCount = 1;
clear_range.levelCount = 1;
// Fail due to explicitly prohibited layout for color clear (only GENERAL and TRANSFER_DST are permitted).
// Since the image is currently not in UNDEFINED layout, this will emit two errors.
m_errorMonitor->SetDesiredError("VUID-vkCmdClearColorImage-imageLayout-01394");
m_errorMonitor->SetDesiredError("VUID-vkCmdClearColorImage-imageLayout-00004");
vk::CmdClearColorImage(m_command_buffer, dst_image, VK_IMAGE_LAYOUT_UNDEFINED, &color_clear_value, 1, &clear_range);
m_errorMonitor->VerifyFound();
// Fail due to provided layout not matching actual current layout for color clear.
m_errorMonitor->SetDesiredError("VUID-vkCmdClearColorImage-imageLayout-00004");
vk::CmdClearColorImage(m_command_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, &color_clear_value, 1, &clear_range);
m_errorMonitor->VerifyFound();
VkClearDepthStencilValue depth_clear_value = {};
clear_range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
// Fail due to explicitly prohibited layout for depth clear (only GENERAL and TRANSFER_DST are permitted).
// Since the image is currently not in UNDEFINED layout, this will emit two errors.
m_errorMonitor->SetDesiredError("VUID-vkCmdClearDepthStencilImage-imageLayout-00012");
m_errorMonitor->SetDesiredError("VUID-vkCmdClearDepthStencilImage-imageLayout-00011");
vk::CmdClearDepthStencilImage(m_command_buffer, depth_image, VK_IMAGE_LAYOUT_UNDEFINED, &depth_clear_value, 1, &clear_range);
m_errorMonitor->VerifyFound();
// Fail due to provided layout not matching actual current layout for depth clear.
m_errorMonitor->SetDesiredError("VUID-vkCmdClearDepthStencilImage-imageLayout-00011");
vk::CmdClearDepthStencilImage(m_command_buffer, depth_image, VK_IMAGE_LAYOUT_GENERAL, &depth_clear_value, 1, &clear_range);
m_errorMonitor->VerifyFound();
VkImageMemoryBarrier image_barrier[1] = {};
// In synchronization2, if oldLayout == newLayout, we're not doing an ILT and these fields don't need to match
// the image's layout.
image_barrier[0] = vku::InitStructHelper();
image_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_barrier[0].newLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_barrier[0].image = src_image;
image_barrier[0].subresourceRange.layerCount = image_create_info.arrayLayers;
image_barrier[0].subresourceRange.levelCount = image_create_info.mipLevels;
image_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 0,
NULL, 1, image_barrier);
// Now cause error due to bad image layout transition in PipelineBarrier
image_barrier[0] = vku::InitStructHelper();
image_barrier[0].oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
image_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
image_barrier[0].image = src_image;
image_barrier[0].subresourceRange.layerCount = image_create_info.arrayLayers;
image_barrier[0].subresourceRange.levelCount = image_create_info.mipLevels;
image_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
m_errorMonitor->SetDesiredError("VUID-VkImageMemoryBarrier-oldLayout-01197");
m_errorMonitor->SetDesiredError("VUID-VkImageMemoryBarrier-oldLayout-01210");
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 0,
NULL, 1, image_barrier);
m_errorMonitor->VerifyFound();
// Finally some layout errors at RenderPass create time
// Just hacking in specific state to get to the errors we want so don't copy this unless you know what you're doing.
VkAttachmentReference attach = {};
VkSubpassDescription subpass = {};
subpass.inputAttachmentCount = 0;
subpass.colorAttachmentCount = 0;
subpass.pDepthStencilAttachment = &attach;
VkRenderPassCreateInfo rpci = vku::InitStructHelper();
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
rpci.attachmentCount = 1;
VkRenderPass rp;
// For this error we need a valid renderpass so create default one
attach.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
attach.attachment = 0;
VkAttachmentDescription attach_desc = {};
attach_desc.format = depth_format;
attach_desc.samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attach_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attach_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
// Can't do a CLEAR load on READ_ONLY initialLayout
attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attach_desc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
attach_desc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
rpci.pAttachments = &attach_desc;
m_errorMonitor->SetDesiredError("VUID-VkAttachmentDescription-format-03283");
vk::CreateRenderPass(device(), &rpci, NULL, &rp);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, CopyColorToDepthOnComputeQueue) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MAINTENANCE_10_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance8);
AddRequiredFeature(vkt::Feature::maintenance10);
RETURN_IF_SKIP(Init());
auto compute_without_graphics_queue_i = m_device->QueueFamily(VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT);
if (!compute_without_graphics_queue_i.has_value()) {
GTEST_SKIP() << "Need a queue that supports compute but not graphics";
}
const bool ds_supports_copy_on_compute_queue = FormatFeatures2AreSupported(
Gpu(), VK_FORMAT_D16_UNORM, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_2_DEPTH_COPY_ON_COMPUTE_QUEUE_BIT_KHR);
if (ds_supports_copy_on_compute_queue) {
GTEST_SKIP() << "Test requires format features to not support depth copy on compute queue";
}
vkt::CommandPool pool(*m_device, *compute_without_graphics_queue_i);
vkt::CommandBuffer cb(*m_device, pool);
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = VK_FORMAT_R16_UINT;
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_TRANSFER_SRC_BIT;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_create_info.flags = 0;
vkt::Image src_image(*m_device, image_create_info, vkt::set_layout);
image_create_info.format = VK_FORMAT_D16_UNORM;
image_create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
vkt::Image depth_image(*m_device, image_create_info, vkt::set_layout);
cb.Begin();
VkImageCopy copy_region{};
copy_region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
copy_region.dstSubresource = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0, 1};
copy_region.srcOffset = {0, 0, 0};
copy_region.dstOffset = {0, 0, 0};
copy_region.extent = {1, 1, 1};
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-commandBuffer-11782");
vk::CmdCopyImage(cb, src_image, VK_IMAGE_LAYOUT_GENERAL, depth_image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, CopyColorToDepthOnTransferQueue) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MAINTENANCE_10_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance8);
AddRequiredFeature(vkt::Feature::maintenance10);
RETURN_IF_SKIP(Init());
auto compute_without_graphics_queue_i =
m_device->QueueFamily(VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
if (!compute_without_graphics_queue_i.has_value()) {
GTEST_SKIP() << "Need a queue that supports transfer but not graphics";
}
const bool ds_supports_copy_on_transfer_queue = FormatFeatures2AreSupported(
Gpu(), VK_FORMAT_D16_UNORM, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_2_DEPTH_COPY_ON_TRANSFER_QUEUE_BIT_KHR);
if (ds_supports_copy_on_transfer_queue) {
GTEST_SKIP() << "Test requires format features to not support depth copy on transfer queue";
}
vkt::CommandPool pool(*m_device, *compute_without_graphics_queue_i);
vkt::CommandBuffer cb(*m_device, pool);
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = VK_FORMAT_R16_UINT;
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_TRANSFER_SRC_BIT;
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_create_info.flags = 0;
vkt::Image src_image(*m_device, image_create_info, vkt::set_layout);
image_create_info.format = VK_FORMAT_D16_UNORM;
image_create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
vkt::Image depth_image(*m_device, image_create_info, vkt::set_layout);
cb.Begin();
VkImageCopy copy_region{};
copy_region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
copy_region.dstSubresource = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0, 1};
copy_region.srcOffset = {0, 0, 0};
copy_region.dstOffset = {0, 0, 0};
copy_region.extent = {1, 1, 1};
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-commandBuffer-11783");
vk::CmdCopyImage(cb, src_image, VK_IMAGE_LAYOUT_GENERAL, depth_image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, StorageImage) {
TEST_DESCRIPTION("Attempt to update a STORAGE_IMAGE descriptor w/o GENERAL layout.");
RETURN_IF_SKIP(Init());
if ((m_device->FormatFeaturesOptimal(VK_FORMAT_R8G8B8A8_UNORM) & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0) {
GTEST_SKIP() << "Device does not support VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; skipped.";
}
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_STORAGE_BIT);
vkt::ImageView view = image.CreateView();
descriptor_set.WriteDescriptorImageInfo(0, view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-04152");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, ArrayLayers) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/1998");
RETURN_IF_SKIP(Init());
RETURN_IF_SKIP(InitRenderTarget());
auto image_ci = vkt::Image::ImageCreateInfo2D(128, 128, 1, 2, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::Image image(*m_device, image_ci);
// layer 0 now VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
// layer 1 is still VK_IMAGE_LAYOUT_UNDEFINED.
m_command_buffer.Begin();
VkImageMemoryBarrier img_barrier = vku::InitStructHelper();
img_barrier.srcAccessMask = 0;
img_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
img_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
img_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
img_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
img_barrier.image = image;
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr,
0, nullptr, 1, &img_barrier);
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
// Get layer with undefined layout
vkt::ImageView image_view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D, 0, 1, 1, 1);
VkShaderObj fs(*m_device, kFragmentSamplerGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
pipe.CreateGraphicsPipeline();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
pipe.descriptor_set_->WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
pipe.descriptor_set_->UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1,
&pipe.descriptor_set_->set_, 0, nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, MultiArrayLayers) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/1998");
RETURN_IF_SKIP(Init());
RETURN_IF_SKIP(InitRenderTarget());
auto image_ci = vkt::Image::ImageCreateInfo2D(128, 128, 1, 2, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::Image image(*m_device, image_ci);
// layer 0 now VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
// layer 1 is still VK_IMAGE_LAYOUT_UNDEFINED.
m_command_buffer.Begin();
VkImageMemoryBarrier img_barrier = vku::InitStructHelper();
img_barrier.srcAccessMask = 0;
img_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
img_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
img_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
img_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
img_barrier.image = image;
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr,
0, nullptr, 1, &img_barrier);
m_command_buffer.End();
m_default_queue->SubmitAndWait(m_command_buffer);
// Bind view to both layers
vkt::ImageView image_view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY, 0, 1, 0, 2);
const char *fs_source = R"glsl(
#version 460
layout(set=0, binding=0) uniform sampler2DArray s;
layout(location=0) out vec4 x;
void main(){
x = texture(s, vec3(1, 1, 1)); // accesses invalid layer
}
)glsl";
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
pipe.CreateGraphicsPipeline();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
pipe.descriptor_set_->WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
pipe.descriptor_set_->UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_, 0, 1,
&pipe.descriptor_set_->set_, 0, nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, DescriptorArrayStaticIndex) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/1998");
RETURN_IF_SKIP(Init());
RETURN_IF_SKIP(InitRenderTarget());
const char *fs_source = R"glsl(
#version 450
#extension GL_EXT_nonuniform_qualifier : enable
// [0] is good layout
// [1] is bad layout
layout(set = 0, binding = 0) uniform sampler2D tex[2];
layout(location = 0) out vec4 uFragColor;
void main(){
uFragColor = texture(tex[1], vec2(0, 0));
}
)glsl";
VkShaderObj vs(*m_device, kVertexDrawPassthroughGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT);
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, VK_SHADER_STAGE_ALL, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.layout = pipeline_layout;
pipe.CreateGraphicsPipeline();
vkt::Image bad_image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::Image good_image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
good_image.SetLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkt::ImageView bad_image_view = bad_image.CreateView(VK_IMAGE_ASPECT_COLOR_BIT);
vkt::ImageView good_image_view = good_image.CreateView(VK_IMAGE_ASPECT_COLOR_BIT);
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
descriptor_set.WriteDescriptorImageInfo(0, good_image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0);
descriptor_set.WriteDescriptorImageInfo(0, bad_image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1);
descriptor_set.UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, LayoutTransitionRenderPassObject) {
TEST_DESCRIPTION("Image barrier must not perform layout transition inside render pass instance");
RETURN_IF_SKIP(Init());
VkSubpassDependency subpass_dep{};
subpass_dep.srcSubpass = 0;
subpass_dep.dstSubpass = 0;
subpass_dep.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
subpass_dep.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
subpass_dep.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
subpass_dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
subpass_dep.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL});
rp.AddColorAttachment(0);
rp.AddSubpassDependency(subpass_dep);
rp.CreateRenderPass();
vkt::Image image(*m_device, 64, 64, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView view = image.CreateView();
vkt::Framebuffer fb(*m_device, rp, 1, &view.handle());
VkImageMemoryBarrier render_pass_barrier = vku::InitStructHelper();
render_pass_barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
render_pass_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
// Attempt to perform image layout transition. It is forbidden if the barrier is inside
// render pass instance (either started with vkCmdBeginRenderPass or vkCmdBeginRendering).
render_pass_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
render_pass_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
render_pass_barrier.image = image;
render_pass_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(rp, fb);
m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier-oldLayout-01181");
vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1,
&render_pass_barrier);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(NegativeImageLayout, LayoutTransitionRenderPassObject2) {
TEST_DESCRIPTION("Image barrier must not perform layout transition inside render pass instance");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
VkSubpassDependency subpass_dep{};
subpass_dep.srcSubpass = 0;
subpass_dep.dstSubpass = 0;
subpass_dep.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
subpass_dep.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
subpass_dep.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
subpass_dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
subpass_dep.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL});
rp.AddColorAttachment(0);
rp.AddSubpassDependency(subpass_dep);
rp.CreateRenderPass();
vkt::Image image(*m_device, 64, 64, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView view = image.CreateView();
vkt::Framebuffer fb(*m_device, rp, 1, &view.handle());
VkImageMemoryBarrier2 render_pass_barrier = vku::InitStructHelper();
render_pass_barrier.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
render_pass_barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
render_pass_barrier.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
render_pass_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
// Attempt to perform image layout transition. It is forbidden if the barrier is inside
// render pass instance (either started with vkCmdBeginRenderPass or vkCmdBeginRendering).
render_pass_barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
render_pass_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
render_pass_barrier.image = image;
render_pass_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(rp, fb);
m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier2-oldLayout-01181");
m_command_buffer.Barrier(render_pass_barrier, VK_DEPENDENCY_BY_REGION_BIT);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(NegativeImageLayout, TimelineSemaphoreOrdering) {
TEST_DESCRIPTION("Timeline semaphore makes execution order different than submission order");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::synchronization2);
AddRequiredFeature(vkt::Feature::timelineSemaphore);
RETURN_IF_SKIP(Init());
if (!m_second_queue) {
GTEST_SKIP() << "Two queues are needed";
}
vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
vkt::Semaphore semaphore(*m_device, VK_SEMAPHORE_TYPE_TIMELINE);
VkImageMemoryBarrier2 layout_transition = vku::InitStructHelper();
layout_transition.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
layout_transition.srcAccessMask = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT;
layout_transition.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
layout_transition.dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT;
layout_transition.image = image;
layout_transition.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
layout_transition.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
layout_transition.newLayout = VK_IMAGE_LAYOUT_GENERAL;
m_command_buffer.Barrier(layout_transition);
m_command_buffer.End();
m_second_command_buffer.Begin();
layout_transition.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
layout_transition.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
m_second_command_buffer.Barrier(layout_transition);
m_second_command_buffer.End();
m_default_queue->Submit2(m_command_buffer, vkt::TimelineWait(semaphore, 1));
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09600");
m_second_queue->Submit2(m_second_command_buffer, vkt::TimelineSignal(semaphore, 1));
m_device->Wait();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, DynamicRenderingColorAttachmentLayout) {
TEST_DESCRIPTION("Color attachment layout does not match expected layout");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
vkt::Image image(*m_device, 128, 128, VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_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_LOAD;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.colorAttachmentCount = 1;
rendering_info.pColorAttachments = &color_attachment;
VkClearColorValue clear_color{};
VkImageSubresourceRange clear_subresource{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
vk::CmdClearColorImage(m_command_buffer, image, VK_IMAGE_LAYOUT_GENERAL, &clear_color, 1, &clear_subresource);
m_errorMonitor->SetDesiredError("VUID-vkCmdBeginRendering-pRenderingInfo-09592");
m_command_buffer.BeginRendering(rendering_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, DynamicRenderingColorAttachmentLayout2) {
TEST_DESCRIPTION("Transition image layout after image was used as dynamic rendering attachment");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
vkt::Image image(*m_device, 128, 128, VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_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_LOAD;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.colorAttachmentCount = 1;
rendering_info.pColorAttachments = &color_attachment;
VkImageMemoryBarrier2 layout_transition = vku::InitStructHelper();
layout_transition.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
layout_transition.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
layout_transition.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
layout_transition.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
// Does not match COLOR_ATTACHMENT_OPTIMAL layout specified by attachment
layout_transition.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
layout_transition.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
layout_transition.image = image;
layout_transition.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
m_command_buffer.EndRendering();
m_errorMonitor->SetDesiredError("VUID-VkImageMemoryBarrier2-oldLayout-01197");
m_command_buffer.Barrier(layout_transition);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeImageLayout, DynamicRenderingDepthAttachmentLayout) {
TEST_DESCRIPTION("Depth attachment layout does not match expected layout");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
const VkFormat depth_format = FindSupportedDepthOnlyFormat(Gpu());
vkt::Image image(*m_device, 128, 128, depth_format,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::ImageView image_view = image.CreateView(VK_IMAGE_ASPECT_DEPTH_BIT);
VkRenderingAttachmentInfo depth_attachment = vku::InitStructHelper();
depth_attachment.imageView = image_view;
depth_attachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.pDepthAttachment = &depth_attachment;
VkClearDepthStencilValue clear_value{};
VkImageSubresourceRange clear_subresource{VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
vk::CmdClearDepthStencilImage(m_command_buffer, image, VK_IMAGE_LAYOUT_GENERAL, &clear_value, 1, &clear_subresource);
m_errorMonitor->SetDesiredError("VUID-vkCmdBeginRendering-pRenderingInfo-09588");
m_command_buffer.BeginRendering(rendering_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, DynamicRenderingDepthAttachmentLayout2) {
TEST_DESCRIPTION("Transition image layout after image was used as dynamic rendering attachment");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
const VkFormat depth_format = FindSupportedDepthOnlyFormat(Gpu());
vkt::Image image(*m_device, 128, 128, depth_format,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::ImageView image_view = image.CreateView(VK_IMAGE_ASPECT_DEPTH_BIT);
VkRenderingAttachmentInfo depth_attachment = vku::InitStructHelper();
depth_attachment.imageView = image_view;
depth_attachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.pDepthAttachment = &depth_attachment;
VkImageMemoryBarrier2 layout_transition = vku::InitStructHelper();
layout_transition.srcStageMask = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT;
layout_transition.srcAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
layout_transition.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
layout_transition.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
// Does not match DEPTH_ATTACHMENT_OPTIMAL layout specified by attachment
layout_transition.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
layout_transition.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
layout_transition.image = image;
layout_transition.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
m_command_buffer.EndRendering();
m_errorMonitor->SetDesiredError("VUID-VkImageMemoryBarrier2-oldLayout-01197");
m_command_buffer.Barrier(layout_transition);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeImageLayout, DynamicRenderingStencilAttachmentLayout) {
TEST_DESCRIPTION("Stencil attachment layout does not match expected layout");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
const VkFormat depth_stencil_format = FindSupportedDepthStencilFormat(Gpu());
vkt::Image image(*m_device, 128, 128, depth_stencil_format,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::ImageView image_view = image.CreateView(VK_IMAGE_ASPECT_STENCIL_BIT);
VkRenderingAttachmentInfo stencil_attachment = vku::InitStructHelper();
stencil_attachment.imageView = image_view;
stencil_attachment.imageLayout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL;
stencil_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
stencil_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.pStencilAttachment = &stencil_attachment;
VkClearDepthStencilValue clear_value{};
VkImageSubresourceRange clear_subresource{VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
vk::CmdClearDepthStencilImage(m_command_buffer, image, VK_IMAGE_LAYOUT_GENERAL, &clear_value, 1, &clear_subresource);
m_errorMonitor->SetDesiredError("VUID-vkCmdBeginRendering-pRenderingInfo-09590");
m_command_buffer.BeginRendering(rendering_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, DynamicRenderingStencilAttachmentLayout2) {
TEST_DESCRIPTION("Transition image layout after image was used as dynamic rendering attachment");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::synchronization2);
RETURN_IF_SKIP(Init());
const VkFormat depth_stencil_format = FindSupportedDepthStencilFormat(Gpu());
vkt::Image image(*m_device, 128, 128, depth_stencil_format,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::ImageView image_view = image.CreateView(VK_IMAGE_ASPECT_STENCIL_BIT);
VkRenderingAttachmentInfo stencil_attachment = vku::InitStructHelper();
stencil_attachment.imageView = image_view;
stencil_attachment.imageLayout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL;
stencil_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
stencil_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.pStencilAttachment = &stencil_attachment;
VkImageMemoryBarrier2 layout_transition = vku::InitStructHelper();
layout_transition.srcStageMask = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT;
layout_transition.srcAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
layout_transition.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
layout_transition.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
// Does not match STENCIL_ATTACHMENT_OPTIMAL layout specified by attachment
layout_transition.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
layout_transition.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
layout_transition.image = image;
layout_transition.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
m_command_buffer.EndRendering();
m_errorMonitor->SetDesiredError("VUID-VkImageMemoryBarrier2-oldLayout-01197");
m_command_buffer.Barrier(layout_transition);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeImageLayout, DynamicRenderingColorAttachmentLayoutSubmitTime) {
TEST_DESCRIPTION("Color attachment layout does not match expected layout. Submit time validation");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
vkt::Image image(*m_device, 128, 128, 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_GENERAL;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.colorAttachmentCount = 1;
rendering_info.pColorAttachments = &color_attachment;
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
m_command_buffer.EndRendering();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdBeginRendering-pRenderingInfo-09592");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, DynamicRenderingDepthAttachmentLayoutSubmitTime) {
TEST_DESCRIPTION("Depth attachment layout does not match expected layout. Submit time validation");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
const VkFormat depth_format = FindSupportedDepthOnlyFormat(Gpu());
vkt::Image image(*m_device, 128, 128, depth_format,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::ImageView image_view = image.CreateView(VK_IMAGE_ASPECT_DEPTH_BIT);
VkRenderingAttachmentInfo depth_attachment = vku::InitStructHelper();
depth_attachment.imageView = image_view;
depth_attachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.pDepthAttachment = &depth_attachment;
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
m_command_buffer.EndRendering();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdBeginRendering-pRenderingInfo-09588");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, DynamicRenderingStencilAttachmentLayoutSubmitTime) {
TEST_DESCRIPTION("Stencil attachment layout does not match expected layout. Submit time validation");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
const VkFormat depth_stencil_format = FindSupportedDepthStencilFormat(Gpu());
vkt::Image image(*m_device, 128, 128, depth_stencil_format,
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::ImageView image_view = image.CreateView(VK_IMAGE_ASPECT_STENCIL_BIT);
VkRenderingAttachmentInfo stencil_attachment = vku::InitStructHelper();
stencil_attachment.imageView = image_view;
stencil_attachment.imageLayout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL;
stencil_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
stencil_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.pStencilAttachment = &stencil_attachment;
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
m_command_buffer.EndRendering();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdBeginRendering-pRenderingInfo-09590");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, DynamicRenderingFragmentShadingRate) {
TEST_DESCRIPTION("FSR attachment layout does not match expected layout");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::synchronization2);
AddRequiredFeature(vkt::Feature::attachmentFragmentShadingRate);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceFragmentShadingRatePropertiesKHR fsr_properties = vku::InitStructHelper();
GetPhysicalDeviceProperties2(fsr_properties);
const VkExtent2D fsr_cell = fsr_properties.minFragmentShadingRateAttachmentTexelSize;
vkt::Image image(*m_device, 128, 128, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView image_view = image.CreateView();
image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
vkt::Image fsr_image(*m_device, 128 / fsr_cell.width, 128 / fsr_cell.height, VK_FORMAT_R8_UINT,
VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::ImageView fsr_image_view = fsr_image.CreateView();
fsr_image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper();
color_attachment.imageView = image_view;
color_attachment.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingFragmentShadingRateAttachmentInfoKHR fsr_attachment = vku::InitStructHelper();
fsr_attachment.imageView = fsr_image_view;
fsr_attachment.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
fsr_attachment.shadingRateAttachmentTexelSize = fsr_cell;
VkRenderingInfo rendering_info = vku::InitStructHelper(&fsr_attachment);
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.colorAttachmentCount = 1;
rendering_info.pColorAttachments = &color_attachment;
VkImageMemoryBarrier2 layout_transition = vku::InitStructHelper();
layout_transition.srcStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
layout_transition.srcAccessMask = VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
layout_transition.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
layout_transition.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
// Does not match VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR layout specified by FSR attachment
layout_transition.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
layout_transition.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
layout_transition.image = fsr_image;
layout_transition.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
m_command_buffer.EndRendering();
m_errorMonitor->SetDesiredError("VUID-VkImageMemoryBarrier2-oldLayout-01197");
m_command_buffer.Barrier(layout_transition);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeImageLayout, DynamicRenderingFragmentShadingRateSubmitTime) {
TEST_DESCRIPTION("FSR attachment layout does not match expected layout. Submit time validation");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceFragmentShadingRatePropertiesKHR fsr_properties = vku::InitStructHelper();
GetPhysicalDeviceProperties2(fsr_properties);
const VkExtent2D fsr_cell = fsr_properties.minFragmentShadingRateAttachmentTexelSize;
vkt::Image image(*m_device, 128, 128, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView image_view = image.CreateView();
image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
vkt::Image fsr_image(*m_device, 128 / fsr_cell.width, 128 / fsr_cell.height, VK_FORMAT_R8_UINT,
VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR);
vkt::ImageView fsr_image_view = fsr_image.CreateView();
fsr_image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper();
color_attachment.imageView = image_view;
color_attachment.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingFragmentShadingRateAttachmentInfoKHR fsr_attachment = vku::InitStructHelper();
fsr_attachment.imageView = fsr_image_view;
fsr_attachment.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
fsr_attachment.shadingRateAttachmentTexelSize = fsr_cell;
VkRenderingInfo rendering_info = vku::InitStructHelper(&fsr_attachment);
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.colorAttachmentCount = 1;
rendering_info.pColorAttachments = &color_attachment;
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
m_command_buffer.EndRendering();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdBeginRendering-imageView-12277");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeImageLayout, DynamicRenderingFragmentDensityMap) {
TEST_DESCRIPTION("FDM attachment layout does not match expected layout");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::synchronization2);
AddRequiredFeature(vkt::Feature::fragmentDensityMap);
RETURN_IF_SKIP(Init());
VkImageCreateInfo image_ci =
vkt::Image::ImageCreateInfo2D(128, 128, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
image_ci.flags = VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT;
vkt::Image image(*m_device, image_ci);
vkt::ImageView image_view = image.CreateView();
vkt::Image fdm_image(*m_device, 128, 128, VK_FORMAT_R8G8_UNORM,
VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::ImageView fdm_image_view = fdm_image.CreateView();
VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper();
color_attachment.imageView = image_view;
color_attachment.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingFragmentDensityMapAttachmentInfoEXT fdm_attachment = vku::InitStructHelper();
fdm_attachment.imageView = fdm_image_view;
fdm_attachment.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT;
VkRenderingInfo rendering_info = vku::InitStructHelper(&fdm_attachment);
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.colorAttachmentCount = 1;
rendering_info.pColorAttachments = &color_attachment;
VkImageMemoryBarrier2 layout_transition = vku::InitStructHelper();
layout_transition.srcStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT;
layout_transition.srcAccessMask = VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT;
layout_transition.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
layout_transition.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
// Does not match VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT layout specified by FDM attachment
layout_transition.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
layout_transition.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
layout_transition.image = fdm_image;
layout_transition.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
m_command_buffer.EndRendering();
m_errorMonitor->SetDesiredError("VUID-VkImageMemoryBarrier2-oldLayout-01197");
m_command_buffer.Barrier(layout_transition);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeImageLayout, DynamicRenderingFragmentDensityMapSubmitTime) {
TEST_DESCRIPTION("FDM attachment layout does not match expected layout. Submit time validation");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::synchronization2);
AddRequiredFeature(vkt::Feature::fragmentDensityMap);
RETURN_IF_SKIP(Init());
VkImageCreateInfo image_ci =
vkt::Image::ImageCreateInfo2D(128, 128, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
image_ci.flags = VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT;
vkt::Image image(*m_device, image_ci);
vkt::ImageView image_view = image.CreateView();
image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
vkt::Image fdm_image(*m_device, 128, 128, VK_FORMAT_R8G8_UNORM,
VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
vkt::ImageView fdm_image_view = fdm_image.CreateView();
fdm_image.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper();
color_attachment.imageView = image_view;
color_attachment.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
VkRenderingFragmentDensityMapAttachmentInfoEXT fdm_attachment = vku::InitStructHelper();
fdm_attachment.imageView = fdm_image_view;
fdm_attachment.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT;
VkRenderingInfo rendering_info = vku::InitStructHelper(&fdm_attachment);
rendering_info.renderArea.extent = {128, 128};
rendering_info.layerCount = 1;
rendering_info.colorAttachmentCount = 1;
rendering_info.pColorAttachments = &color_attachment;
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
m_command_buffer.EndRendering();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdBeginRendering-imageView-12276");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}