| /* |
| * Copyright (c) 2023-2025 LunarG, Inc. |
| * Copyright (c) 2023-2025 Valve Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| */ |
| |
| #include "../framework/layer_validation_tests.h" |
| #include "../framework/pipeline_helper.h" |
| |
| class NegativeShaderImageAccess : public VkLayerTest {}; |
| |
| TEST_F(NegativeShaderImageAccess, FunctionOpImage) { |
| TEST_DESCRIPTION("Use Component Format mismatch to test image access edge cases"); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| // layout(set=0, binding=0) uniform isampler2D s; |
| // vec4 foo(isampler2D s) { |
| // return texelFetch(s, ivec2(0), 0); |
| // } |
| // void main() { |
| // color = foo(s); |
| // } |
| // |
| // but instead of passing the OpTypePointer, passes a OpImage to function |
| const char *fsSource = R"( |
| OpCapability Shader |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" %color |
| OpExecutionMode %main OriginUpperLeft |
| OpDecorate %color Location 0 |
| OpDecorate %s_0 DescriptorSet 0 |
| OpDecorate %s_0 Binding 0 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %int = OpTypeInt 32 1 |
| %7 = OpTypeImage %int 2D 0 0 0 1 Unknown |
| %8 = OpTypeSampledImage %7 |
| %_ptr_UniformConstant_8 = OpTypePointer UniformConstant %8 |
| %float = OpTypeFloat 32 |
| %v4float = OpTypeVector %float 4 |
| %12 = OpTypeFunction %v4float %7 |
| %v2int = OpTypeVector %int 2 |
| %int_0 = OpConstant %int 0 |
| %19 = OpConstantComposite %v2int %int_0 %int_0 |
| %v4int = OpTypeVector %int 4 |
| %_ptr_Output_v4float = OpTypePointer Output %v4float |
| %color = OpVariable %_ptr_Output_v4float Output |
| %s_0 = OpVariable %_ptr_UniformConstant_8 UniformConstant |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| %16 = OpLoad %8 %s_0 |
| %20 = OpImage %7 %16 |
| %29 = OpFunctionCall %v4float %foo_is21_ %20 |
| OpStore %color %29 |
| OpReturn |
| OpFunctionEnd |
| %foo_is21_ = OpFunction %v4float None %12 |
| %s = OpFunctionParameter %7 |
| %15 = OpLabel |
| %22 = OpImageFetch %v4int %s %19 Lod %int_0 |
| %23 = OpConvertSToF %v4float %22 |
| OpReturnValue %23 |
| OpFunctionEnd |
| )"; |
| VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| |
| vkt::Image image(*m_device, 16, 16, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::ImageView imageView = image.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| OneOffDescriptorSet descriptor_set(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, imageView, sampler); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| 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); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-format-07753"); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeShaderImageAccess, ComponentTypeMismatchFunctionTwoArgs) { |
| TEST_DESCRIPTION("Pass a signed and unsinged sampler, and use the incorrect one."); |
| |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| const char *fsSource = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform isampler2D s; // accessed |
| layout(set=0, binding=1) uniform usampler2D u; // not accessed |
| layout(location=0) out vec4 color; |
| |
| vec4 foo(isampler2D _s, usampler2D _u) { |
| return texelFetch(_s, ivec2(0), 0); |
| } |
| void main() { |
| color = foo(s, u); |
| } |
| )glsl"; |
| VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| vkt::Image image(*m_device, 16, 16, VK_FORMAT_R8G8B8A8_UINT, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::ImageView imageView = image.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| OneOffDescriptorSet descriptor_set(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, imageView, sampler); |
| descriptor_set.WriteDescriptorImageInfo(1, imageView, sampler); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| 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); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-format-07753"); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeShaderImageAccess, UnnormalizedCoordinatesFunction) { |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| const char *fsSource = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) uniform sampler2D tex; |
| |
| vec4 foo(sampler2D func_sampler) { |
| return textureLodOffset(func_sampler, vec2(0), 0, ivec2(0)); |
| } |
| |
| void main() { |
| vec4 x = foo(tex); |
| } |
| )glsl"; |
| VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| CreatePipelineHelper g_pipe(*this); |
| g_pipe.shader_stages_ = {g_pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| g_pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}; |
| g_pipe.CreateGraphicsPipeline(); |
| |
| VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; |
| VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; |
| auto image_ci = vkt::Image::ImageCreateInfo2D(128, 128, 1, 1, format, usage); |
| vkt::Image image(*m_device, image_ci, vkt::set_layout); |
| vkt::ImageView view_pass = image.CreateView(); |
| |
| VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo(); |
| sampler_ci.unnormalizedCoordinates = VK_TRUE; |
| sampler_ci.maxLod = 0; |
| vkt::Sampler sampler(*m_device, sampler_ci); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(0, view_pass, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); |
| g_pipe.descriptor_set_->UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_, 0, 1, |
| &g_pipe.descriptor_set_->set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08611"); |
| vk::CmdDraw(m_command_buffer, 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeShaderImageAccess, MultisampleMismatchWithPipeline) { |
| TEST_DESCRIPTION("Shader uses Multisample, but image view isn't."); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| const char *fsSource = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform sampler2DMS s; |
| layout(location=0) out vec4 color; |
| void main() { |
| color = texelFetch(s, ivec2(0), 0); |
| } |
| )glsl"; |
| VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| vkt::Image image(*m_device, 16, 16, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::ImageView imageView = image.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| OneOffDescriptorSet descriptor_set(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, imageView, sampler); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| 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); |
| |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-samples-08726"); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeShaderImageAccess, AliasImageMultisample) { |
| TEST_DESCRIPTION("Same binding used for Multisampling and non-Multisampling"); |
| RETURN_IF_SKIP(Init()); |
| |
| const char *cs_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_samplerless_texture_functions : require |
| |
| layout(set = 0, binding = 0) uniform texture2DMS BaseTextureMS; |
| layout(set = 0, binding = 0) uniform texture2D BaseTexture; |
| layout(set = 0, binding = 1) uniform sampler BaseTextureSampler; |
| layout(set = 0, binding = 2) buffer SSBO { vec4 dummy; }; |
| layout (constant_id = 0) const int path = 0; // always zero, but prevents dead code elimination |
| |
| void main() { |
| dummy = texture(sampler2D(BaseTexture, BaseTextureSampler), vec2(0)); |
| if (path > 10) { |
| // Without descriptor indexing, this is invalid because it is staticlaly used |
| dummy += texelFetch(BaseTextureMS, ivec2(0), 0); |
| } |
| } |
| )glsl"; |
| |
| OneOffDescriptorSet descriptor_set(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| vkt::Buffer buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| auto image_ci = vkt::Image::ImageCreateInfo2D(64, 64, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::Image image(*m_device, image_ci, vkt::set_layout); |
| vkt::ImageView image_view = image.CreateView(); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| descriptor_set.WriteDescriptorImageInfo(1, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER); |
| descriptor_set.WriteDescriptorBufferInfo(2, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT); |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| 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); |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-samples-08726"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeShaderImageAccess, NonMultisampleMismatchWithPipeline) { |
| TEST_DESCRIPTION("Shader uses non-Multisample, but image view is Multisample."); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| const char *fsSource = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform sampler2D s; |
| layout(location=0) out vec4 color; |
| void main() { |
| color = texelFetch(s, ivec2(0), 0); |
| } |
| )glsl"; |
| VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| 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 = 1; |
| image_create_info.samples = VK_SAMPLE_COUNT_4_BIT; |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| vkt::Image image(*m_device, image_create_info, vkt::set_layout); |
| vkt::ImageView imageView = image.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| OneOffDescriptorSet descriptor_set(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, imageView, sampler); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| 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); |
| |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-samples-08725"); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeShaderImageAccess, NonMultisampleMismatchWithPipelineArray) { |
| TEST_DESCRIPTION("Shader uses non-Multisample, but image view is Multisample."); |
| RETURN_IF_SKIP(Init()); |
| |
| auto image_create_info = vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::Image good_image(*m_device, image_create_info, vkt::set_layout); |
| vkt::ImageView good_image_view = good_image.CreateView(); |
| |
| image_create_info.samples = VK_SAMPLE_COUNT_4_BIT; |
| vkt::Image bad_image(*m_device, image_create_info, vkt::set_layout); |
| vkt::ImageView bad_image_view = bad_image.CreateView(); |
| |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); |
| |
| OneOffDescriptorSet descriptor_set(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| 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.WriteDescriptorBufferInfo(1, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| // mySampler[0] is good |
| // mySampler[1] is bad |
| layout(set=0, binding=0) uniform sampler2D mySampler[2]; |
| layout(set=0, binding=1) buffer SSBO { |
| int index; |
| vec4 out_value; |
| }; |
| void main() { |
| out_value = texelFetch(mySampler[index], ivec2(0), 0); |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT); |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set.set_, 0, |
| nullptr); |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-samples-08725"); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeShaderImageAccess, MultipleFunctionCalls) { |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| PFN_vkSetPhysicalDeviceFormatPropertiesEXT fpvkSetPhysicalDeviceFormatPropertiesEXT = nullptr; |
| PFN_vkGetOriginalPhysicalDeviceFormatPropertiesEXT fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT = nullptr; |
| if (!LoadDeviceProfileLayer(fpvkSetPhysicalDeviceFormatPropertiesEXT, fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT)) { |
| GTEST_SKIP() << "Failed to load device profile layer."; |
| } |
| |
| const VkFormat good_format = VK_FORMAT_R8G8B8A8_UNORM; |
| const VkFormat bad_format = VK_FORMAT_B8G8R8A8_UNORM; |
| |
| VkFormatProperties formatProps; |
| fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT(Gpu(), bad_format, &formatProps); |
| formatProps.optimalTilingFeatures = (formatProps.optimalTilingFeatures & ~VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT); |
| fpvkSetPhysicalDeviceFormatPropertiesEXT(Gpu(), bad_format, formatProps); |
| |
| fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT(Gpu(), good_format, &formatProps); |
| formatProps.optimalTilingFeatures |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; |
| fpvkSetPhysicalDeviceFormatPropertiesEXT(Gpu(), good_format, formatProps); |
| |
| vkt::Image bad_image(*m_device, 128, 128, bad_format, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::ImageView bad_view = bad_image.CreateView(); |
| |
| vkt::Image good_image(*m_device, 128, 128, good_format, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::ImageView good_view = good_image.CreateView(); |
| |
| VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo(); |
| sampler_ci.minFilter = VK_FILTER_LINEAR; // turned off feature bit for test |
| sampler_ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; |
| sampler_ci.compareEnable = VK_FALSE; |
| vkt::Sampler sampler(*m_device, sampler_ci); |
| |
| const char *fs_source = R"glsl( |
| #version 450 |
| layout (set=0, binding=0) uniform sampler2D good_a; |
| layout (set=0, binding=1) uniform sampler2D bad; |
| layout (set=0, binding=2) uniform sampler2D good_b; |
| layout(location=0) out vec4 color; |
| |
| vec4 Foo(sampler2D x) { |
| return texture(x, gl_FragCoord.xy); |
| } |
| |
| void main() { |
| color = Foo(good_a) + Foo(bad) + Foo(good_b); |
| } |
| )glsl"; |
| VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| OneOffDescriptorSet descriptor_set(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, good_view, sampler); |
| descriptor_set.WriteDescriptorImageInfo(1, bad_view, sampler); |
| descriptor_set.WriteDescriptorImageInfo(2, good_view, sampler); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_[1] = fs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0, |
| nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-magFilter-04553"); |
| vk::CmdDraw(m_command_buffer, 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeShaderImageAccess, AliasImageBinding) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7677"); |
| RETURN_IF_SKIP(Init()); |
| |
| const char *csSource = R"glsl( |
| #version 460 |
| #extension GL_EXT_samplerless_texture_functions : require |
| |
| // This should be an GLSL error, if both of these are accessed (without PARTIALLY_BOUND), you need to satisfy both, which is impossible |
| layout(set = 0, binding = 0) uniform texture2D float_textures[2]; |
| layout(set = 0, binding = 0) uniform utexture2D uint_textures[2]; |
| layout(set = 0, binding = 1) buffer output_buffer { vec4 data; }; // avoid optimization |
| |
| void main() { |
| const vec4 value = texelFetch(float_textures[0], ivec2(0), 0); |
| const uint mask_a = texelFetch(uint_textures[1], ivec2(0), 0).x; |
| data = mask_a > 0 ? value : vec4(0.0); |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}}; |
| pipe.cs_ = VkShaderObj(*m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT); |
| pipe.CreateComputePipeline(); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(64, 64, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::Image float_image(*m_device, image_ci, vkt::set_layout); |
| vkt::ImageView float_image_view = float_image.CreateView(); |
| |
| image_ci.format = VK_FORMAT_R8G8B8A8_UINT; |
| vkt::Image uint_image(*m_device, image_ci, vkt::set_layout); |
| vkt::ImageView uint_image_view = uint_image.CreateView(); |
| |
| vkt::Buffer buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); |
| |
| pipe.descriptor_set_.WriteDescriptorImageInfo(0, float_image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, |
| VK_IMAGE_LAYOUT_GENERAL, 0); |
| pipe.descriptor_set_.WriteDescriptorImageInfo(0, uint_image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, |
| VK_IMAGE_LAYOUT_GENERAL, 1); |
| pipe.descriptor_set_.WriteDescriptorBufferInfo(1, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| 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); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-format-07753", 2); // one for index [0] and [1] |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| TEST_F(NegativeShaderImageAccess, AliasImageBindingArrayType) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9553"); |
| RETURN_IF_SKIP(Init()); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| // This should be an GLSL error, if both of these are accessed (without PARTIALLY_BOUND), you need to satisfy both, which is impossible |
| layout(set = 0, binding = 0) uniform sampler2D uPlanetTextures[2]; |
| layout(set = 0, binding = 0) uniform sampler2DArray uPlanetArrayTextures[2]; |
| void main() { |
| vec4 color1 = texture(uPlanetTextures[0], vec2(0)); |
| vec4 color2 = texture(uPlanetArrayTextures[1], vec3(0)); |
| } |
| )glsl"; |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(128, 128, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::Image image(*m_device, image_ci, vkt::set_layout); |
| vkt::ImageView image_view = image.CreateView(); |
| |
| vkt::Image image_array(*m_device, image_ci, vkt::set_layout); |
| vkt::ImageView image_view_array = image_array.CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}}); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| descriptor_set.WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); |
| descriptor_set.WriteDescriptorImageInfo(0, image_view_array, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT); |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set.set_, 0, |
| nullptr); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-viewType-07752", 2); // one for each descriptor |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeShaderImageAccess, SampledImageShareBinding) { |
| TEST_DESCRIPTION("Make sure the binding from the correct set it detected"); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| const char *fs_source = R"glsl( |
| #version 460 |
| layout (set = 0, binding = 0) uniform texture2D kTextures2D; |
| layout (set = 0, binding = 1) uniform sampler kSamplers; |
| layout (set = 1, binding = 0) uniform textureCube kTexturesCube; |
| |
| vec4 textureBindlessCube(textureCube texture_in, sampler sampler_in) { |
| return texture(samplerCube(texture_in, sampler_in), vec3(0.0)); |
| } |
| |
| layout (location=0) out vec4 color; |
| |
| void main() { |
| color = textureBindlessCube(kTexturesCube, kSamplers); |
| } |
| )glsl"; |
| VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| OneOffDescriptorSet descriptor_set_0(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| OneOffDescriptorSet descriptor_set_1(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set_0.layout_, &descriptor_set_1.layout_}); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::Image image_2d(*m_device, image_ci); |
| vkt::ImageView image_view_2d = image_2d.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| descriptor_set_0.WriteDescriptorImageInfo(0, image_view_2d, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| descriptor_set_0.WriteDescriptorImageInfo(1, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER); |
| descriptor_set_0.UpdateDescriptorSets(); |
| |
| descriptor_set_1.WriteDescriptorImageInfo(0, image_view_2d, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| descriptor_set_1.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set_0.set_, 0, |
| nullptr); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 1, 1, &descriptor_set_1.set_, 0, |
| nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-viewType-07752"); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeShaderImageAccess, SampledImageShareBindingArray) { |
| TEST_DESCRIPTION("two descriptor sets aliased, so seems valid in GLSL"); |
| AddRequiredFeature(vkt::Feature::imageCubeArray); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| const char *fs_source = R"glsl( |
| #version 460 |
| layout (set = 0, binding = 0) uniform texture2D kTextures2D[2]; |
| layout (set = 0, binding = 1) uniform sampler kSamplers[2]; |
| layout (set = 1, binding = 0) uniform textureCube kTexturesCube[2]; |
| layout (location=0) out vec4 color; |
| |
| void main() { |
| color = texture(samplerCube(kTexturesCube[1], kSamplers[0]), vec3(0.0)); |
| } |
| )glsl"; |
| VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| OneOffDescriptorSet descriptor_set(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLER, 2, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_, &descriptor_set.layout_}); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::Image image_2d(*m_device, image_ci); |
| vkt::ImageView image_view_2d = image_2d.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| image_ci.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; |
| image_ci.arrayLayers = 6; |
| vkt::Image image_cube(*m_device, image_ci); |
| vkt::ImageView image_view_cube = image_cube.CreateView(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, image_view_cube, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); |
| // Set kTexturesCube[1] to be a non-Cube image view |
| descriptor_set.WriteDescriptorImageInfo(0, image_view_2d, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1); |
| descriptor_set.WriteDescriptorImageInfo(1, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); |
| descriptor_set.WriteDescriptorImageInfo(1, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| const VkDescriptorSet sets[2] = {descriptor_set.set_, descriptor_set.set_}; |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 2, sets, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-viewType-07752"); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeShaderImageAccess, SampledImageShareBindingArrayFunction) { |
| TEST_DESCRIPTION("two descriptor sets aliased, so seems valid in GLSL, but index is through function"); |
| AddRequiredFeature(vkt::Feature::imageCubeArray); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| const char *fs_source = R"glsl( |
| #version 460 |
| layout (set = 0, binding = 0) uniform texture2D kTextures2D[2]; |
| layout (set = 0, binding = 1) uniform sampler kSamplers[2]; |
| layout (set = 1, binding = 0) uniform textureCube kTexturesCube[2]; |
| |
| vec4 textureBindlessCube(uint textureid, uint samplerid) { |
| return texture(samplerCube(kTexturesCube[textureid], kSamplers[samplerid]), vec3(0.0)); |
| } |
| |
| layout (location=0) out vec4 color; |
| |
| void main() { |
| color = textureBindlessCube(1, 0); |
| } |
| )glsl"; |
| VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| OneOffDescriptorSet descriptor_set(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLER, 2, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_, &descriptor_set.layout_}); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::Image image_2d(*m_device, image_ci); |
| vkt::ImageView image_view_2d = image_2d.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| image_ci.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; |
| image_ci.arrayLayers = 6; |
| vkt::Image image_cube(*m_device, image_ci); |
| vkt::ImageView image_view_cube = image_cube.CreateView(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, image_view_cube, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); |
| // Set kTexturesCube[1] to be a non-Cube image view |
| descriptor_set.WriteDescriptorImageInfo(0, image_view_2d, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1); |
| descriptor_set.WriteDescriptorImageInfo(1, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); |
| descriptor_set.WriteDescriptorImageInfo(1, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| const VkDescriptorSet sets[2] = {descriptor_set.set_, descriptor_set.set_}; |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 2, sets, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-viewType-07752"); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| // Currently not detecting through functions correctly |
| TEST_F(NegativeShaderImageAccess, DISABLED_FunctionDescriptorIndexing) { |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| const char *fs_source = R"glsl( |
| #version 460 |
| layout (set = 0, binding = 0) uniform sampler2D tex[3]; |
| layout (location=0) out vec4 color; |
| |
| vec4 foo(uint i) { |
| return texelFetch(tex[i], ivec2(0), 0); |
| } |
| |
| void main() { |
| color = foo(99); |
| } |
| )glsl"; |
| VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| OneOffDescriptorSet descriptor_set(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 3, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_, &descriptor_set.layout_}); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::Image image(*m_device, image_ci); |
| vkt::ImageView image_view = image.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); |
| descriptor_set.WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1); |
| descriptor_set.WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 2); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0, |
| nullptr); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |