| /* |
| * Copyright (c) 2015-2024 The Khronos Group Inc. |
| * Copyright (c) 2015-2024 Valve Corporation |
| * Copyright (c) 2015-2024 LunarG, Inc. |
| * Copyright (c) 2015-2024 Google, Inc. |
| * Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| */ |
| |
| #include "../framework/layer_validation_tests.h" |
| #include "../framework/pipeline_helper.h" |
| #include "../framework/descriptor_helper.h" |
| |
| class NegativeSampler : public VkLayerTest {}; |
| |
| TEST_F(NegativeSampler, MirrorClampToEdgeNotEnabled) { |
| TEST_DESCRIPTION("Validation should catch using CLAMP_TO_EDGE addressing mode if the extension is not enabled."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_0); |
| RETURN_IF_SKIP(Init()); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| // Set the modes to cause the error |
| sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; |
| // Prior to 1.2 we get the implicit VU |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-addressModeU-parameter"); |
| } |
| |
| TEST_F(NegativeSampler, MirrorClampToEdgeNotEnabled12) { |
| TEST_DESCRIPTION("Validation using CLAMP_TO_EDGE for Vulkan 1.2 without the samplerMirrorClampToEdge feature enabled."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(Init()); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-addressModeU-01079"); |
| } |
| |
| TEST_F(NegativeSampler, AnisotropyFeatureDisabled) { |
| TEST_DESCRIPTION("Validation should check anisotropy parameters are correct with samplerAnisotropy disabled."); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkSamplerCreateInfo-anisotropyEnable-01070"); |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| // With the samplerAnisotropy disable, the sampler must not enable it. |
| sampler_info.anisotropyEnable = VK_TRUE; |
| vkt::Sampler sampler(*m_device, sampler_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeSampler, AnisotropyFeatureEnabled) { |
| TEST_DESCRIPTION("Validation must check several conditions that apply only when Anisotropy is enabled."); |
| AddRequiredFeature(vkt::Feature::samplerAnisotropy); |
| RETURN_IF_SKIP(Init()); |
| VkSamplerCreateInfo sampler_info_ref = SafeSaneSamplerCreateInfo(); |
| sampler_info_ref.anisotropyEnable = VK_TRUE; |
| VkSamplerCreateInfo sampler_info = sampler_info_ref; |
| |
| // maxAnisotropy out-of-bounds low. |
| sampler_info.maxAnisotropy = NearestSmaller(1.0F); |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-anisotropyEnable-01071"); |
| sampler_info.maxAnisotropy = sampler_info_ref.maxAnisotropy; |
| |
| // maxAnisotropy out-of-bounds high. |
| sampler_info.maxAnisotropy = NearestGreater(m_device->Physical().limits_.maxSamplerAnisotropy); |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-anisotropyEnable-01071"); |
| sampler_info.maxAnisotropy = sampler_info_ref.maxAnisotropy; |
| |
| // Both anisotropy and unnormalized coords enabled |
| sampler_info.unnormalizedCoordinates = VK_TRUE; |
| // If unnormalizedCoordinates is VK_TRUE, minLod and maxLod must be zero |
| sampler_info.minLod = 0; |
| sampler_info.maxLod = 0; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01076"); |
| sampler_info.unnormalizedCoordinates = sampler_info_ref.unnormalizedCoordinates; |
| } |
| |
| TEST_F(NegativeSampler, AnisotropyFeatureEnabledCubic) { |
| TEST_DESCRIPTION("Validation must check several conditions that apply only when Anisotropy is enabled."); |
| AddRequiredExtensions(VK_IMG_FILTER_CUBIC_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::samplerAnisotropy); |
| RETURN_IF_SKIP(Init()); |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.anisotropyEnable = VK_TRUE; |
| // If unnormalizedCoordinates is VK_TRUE, minLod and maxLod must be zero |
| sampler_info.minLod = 0; |
| sampler_info.maxLod = 0; |
| |
| sampler_info.minFilter = VK_FILTER_CUBIC_IMG; |
| sampler_info.magFilter = VK_FILTER_NEAREST; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-magFilter-01081"); |
| |
| sampler_info.minFilter = VK_FILTER_NEAREST; |
| sampler_info.magFilter = VK_FILTER_CUBIC_IMG; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-magFilter-01081"); |
| } |
| |
| TEST_F(NegativeSampler, UnnormalizedCoordinatesEnabled) { |
| TEST_DESCRIPTION("Validate restrictions on sampler parameters when unnormalizedCoordinates is true."); |
| RETURN_IF_SKIP(InitFramework(&kDisableMessageLimit)); |
| RETURN_IF_SKIP(InitState()); |
| VkSamplerCreateInfo sampler_info_ref = SafeSaneSamplerCreateInfo(); |
| sampler_info_ref.unnormalizedCoordinates = VK_TRUE; |
| sampler_info_ref.minLod = 0.0f; |
| sampler_info_ref.maxLod = 0.0f; |
| VkSamplerCreateInfo sampler_info = sampler_info_ref; |
| |
| // min and mag filters must be the same |
| sampler_info.minFilter = VK_FILTER_NEAREST; |
| sampler_info.magFilter = VK_FILTER_LINEAR; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01072"); |
| std::swap(sampler_info.minFilter, sampler_info.magFilter); |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01072"); |
| sampler_info = sampler_info_ref; |
| |
| // mipmapMode must be NEAREST |
| sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01073"); |
| sampler_info = sampler_info_ref; |
| |
| // minlod and maxlod must be zero |
| sampler_info.maxLod = 3.14159f; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01074"); |
| sampler_info.minLod = 2.71828f; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01074"); |
| sampler_info = sampler_info_ref; |
| |
| // addressModeU and addressModeV must both be CLAMP_TO_EDGE or CLAMP_TO_BORDER |
| // checks all 12 invalid combinations out of 16 total combinations |
| const std::array<VkSamplerAddressMode, 4> kAddressModes = {{ |
| VK_SAMPLER_ADDRESS_MODE_REPEAT, |
| VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, |
| }}; |
| for (const auto umode : kAddressModes) { |
| for (const auto vmode : kAddressModes) { |
| if ((umode != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE && umode != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER) || |
| (vmode != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE && vmode != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER)) { |
| sampler_info.addressModeU = umode; |
| sampler_info.addressModeV = vmode; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01075"); |
| } |
| } |
| } |
| sampler_info = sampler_info_ref; |
| |
| // VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01076 is tested in AnisotropyFeatureEnabled above |
| // Since it requires checking/enabling the anisotropic filtering feature, it's easier to do it |
| // with the other anisotropic tests. |
| |
| // compareEnable must be VK_FALSE |
| sampler_info.compareEnable = VK_TRUE; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01077"); |
| sampler_info = sampler_info_ref; |
| } |
| |
| TEST_F(NegativeSampler, BasicUsage) { |
| TEST_DESCRIPTION("Checks various cases where VkSamplerCreateInfo is invalid"); |
| RETURN_IF_SKIP(Init()); |
| |
| // reference to reset values between test cases |
| VkSamplerCreateInfo const sampler_info_ref = SafeSaneSamplerCreateInfo(); |
| VkSamplerCreateInfo sampler_info = sampler_info_ref; |
| |
| // Mix up Lod values |
| sampler_info.minLod = 4.0f; |
| sampler_info.maxLod = 1.0f; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-maxLod-01973"); |
| sampler_info.minLod = sampler_info_ref.minLod; |
| sampler_info.maxLod = sampler_info_ref.maxLod; |
| |
| // Larger mipLodBias than max limit |
| sampler_info.mipLodBias = NearestGreater(m_device->Physical().limits_.maxSamplerLodBias); |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-mipLodBias-01069"); |
| sampler_info.mipLodBias = sampler_info_ref.mipLodBias; |
| } |
| |
| TEST_F(NegativeSampler, AllocationCount) { |
| VkResult err = VK_SUCCESS; |
| const int max_samplers = 32; |
| VkSampler samplers[max_samplers + 1]; |
| |
| RETURN_IF_SKIP(InitFramework()); |
| |
| PFN_vkSetPhysicalDeviceLimitsEXT fpvkSetPhysicalDeviceLimitsEXT = nullptr; |
| PFN_vkGetOriginalPhysicalDeviceLimitsEXT fpvkGetOriginalPhysicalDeviceLimitsEXT = nullptr; |
| if (!LoadDeviceProfileLayer(fpvkSetPhysicalDeviceLimitsEXT, fpvkGetOriginalPhysicalDeviceLimitsEXT)) { |
| GTEST_SKIP() << "Failed to load device profile layer."; |
| } |
| VkPhysicalDeviceProperties props; |
| fpvkGetOriginalPhysicalDeviceLimitsEXT(Gpu(), &props.limits); |
| if (props.limits.maxSamplerAllocationCount > max_samplers) { |
| props.limits.maxSamplerAllocationCount = max_samplers; |
| fpvkSetPhysicalDeviceLimitsEXT(Gpu(), &props.limits); |
| } |
| RETURN_IF_SKIP(InitState()); |
| m_errorMonitor->SetDesiredError("VUID-vkCreateSampler-maxSamplerAllocationCount-04110"); |
| |
| VkSamplerCreateInfo sampler_create_info = SafeSaneSamplerCreateInfo(); |
| |
| int i; |
| for (i = 0; i <= max_samplers; i++) { |
| err = vk::CreateSampler(device(), &sampler_create_info, NULL, &samplers[i]); |
| if (err != VK_SUCCESS) { |
| break; |
| } |
| } |
| m_errorMonitor->VerifyFound(); |
| |
| for (int j = 0; j < i; j++) { |
| vk::DestroySampler(device(), samplers[j], NULL); |
| } |
| } |
| |
| TEST_F(NegativeSampler, ImageViewFormatUnsupportedFilter) { |
| TEST_DESCRIPTION( |
| "Create sampler with a filter and use with image view using a format that does not support the sampler filter."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddOptionalExtensions(VK_IMG_FILTER_CUBIC_EXTENSION_NAME); |
| RETURN_IF_SKIP(Init()); |
| const bool cubic_support = IsExtensionsEnabled(VK_IMG_FILTER_CUBIC_EXTENSION_NAME); |
| |
| enum FormatTypes { FLOAT, SINT, UINT }; |
| |
| struct TestFilterType { |
| VkFilter filter = VK_FILTER_LINEAR; |
| VkFormatFeatureFlagBits required_format_feature = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; |
| VkImageTiling tiling = VK_IMAGE_TILING_LINEAR; |
| VkFormat format = VK_FORMAT_UNDEFINED; |
| FormatTypes format_type; |
| std::string err_msg; |
| }; |
| |
| std::vector<std::pair<VkFormat, FormatTypes>> formats_to_check({{VK_FORMAT_R8_UNORM, FLOAT}, |
| {VK_FORMAT_R8_SNORM, FLOAT}, |
| {VK_FORMAT_R8_SRGB, FLOAT}, |
| {VK_FORMAT_R8G8_UNORM, FLOAT}, |
| {VK_FORMAT_R8G8_SNORM, FLOAT}, |
| {VK_FORMAT_R8G8_SRGB, FLOAT}, |
| {VK_FORMAT_R8G8B8_UNORM, FLOAT}, |
| {VK_FORMAT_R8G8B8_SNORM, FLOAT}, |
| {VK_FORMAT_R8G8B8_SRGB, FLOAT}, |
| {VK_FORMAT_R8G8B8A8_UNORM, FLOAT}, |
| {VK_FORMAT_R8G8B8A8_SNORM, FLOAT}, |
| {VK_FORMAT_R8G8B8A8_SRGB, FLOAT}, |
| {VK_FORMAT_B8G8R8A8_UNORM, FLOAT}, |
| {VK_FORMAT_B8G8R8A8_SNORM, FLOAT}, |
| {VK_FORMAT_B8G8R8A8_SRGB, FLOAT}, |
| {VK_FORMAT_R16_UNORM, FLOAT}, |
| {VK_FORMAT_R16_SNORM, FLOAT}, |
| {VK_FORMAT_R16_SFLOAT, FLOAT}, |
| {VK_FORMAT_R16G16_UNORM, FLOAT}, |
| {VK_FORMAT_R16G16_SNORM, FLOAT}, |
| {VK_FORMAT_R16G16_SFLOAT, FLOAT}, |
| {VK_FORMAT_R16G16B16_UNORM, FLOAT}, |
| {VK_FORMAT_R16G16B16_SNORM, FLOAT}, |
| {VK_FORMAT_R16G16B16_SFLOAT, FLOAT}, |
| {VK_FORMAT_R16G16B16A16_UNORM, FLOAT}, |
| {VK_FORMAT_R16G16B16A16_SNORM, FLOAT}, |
| {VK_FORMAT_R16G16B16A16_SFLOAT, FLOAT}, |
| {VK_FORMAT_R32_SFLOAT, FLOAT}, |
| {VK_FORMAT_R32G32_SFLOAT, FLOAT}, |
| {VK_FORMAT_R32G32B32_SFLOAT, FLOAT}, |
| {VK_FORMAT_R32G32B32A32_SFLOAT, FLOAT}, |
| {VK_FORMAT_R64_SFLOAT, FLOAT}, |
| {VK_FORMAT_R64G64_SFLOAT, FLOAT}, |
| {VK_FORMAT_R64G64B64_SFLOAT, FLOAT}, |
| {VK_FORMAT_R64G64B64A64_SFLOAT, FLOAT}, |
| {VK_FORMAT_R8_SINT, SINT}, |
| {VK_FORMAT_R8G8_SINT, SINT}, |
| {VK_FORMAT_R8G8B8_SINT, SINT}, |
| {VK_FORMAT_R8G8B8A8_SINT, SINT}, |
| {VK_FORMAT_B8G8R8A8_SINT, SINT}, |
| {VK_FORMAT_R16_SINT, SINT}, |
| {VK_FORMAT_R16G16_SINT, SINT}, |
| {VK_FORMAT_R16G16B16_SINT, SINT}, |
| {VK_FORMAT_R16G16B16A16_SINT, SINT}, |
| {VK_FORMAT_R32_SINT, SINT}, |
| {VK_FORMAT_R32G32_SINT, SINT}, |
| {VK_FORMAT_R32G32B32_SINT, SINT}, |
| {VK_FORMAT_R32G32B32A32_SINT, SINT}, |
| {VK_FORMAT_R64_SINT, SINT}, |
| {VK_FORMAT_R64G64_SINT, SINT}, |
| {VK_FORMAT_R64G64B64_SINT, SINT}, |
| {VK_FORMAT_R64G64B64A64_SINT, SINT}, |
| {VK_FORMAT_R8_UINT, UINT}, |
| {VK_FORMAT_R8G8_UINT, UINT}, |
| {VK_FORMAT_R8G8B8_UINT, UINT}, |
| {VK_FORMAT_R8G8B8A8_UINT, UINT}, |
| {VK_FORMAT_B8G8R8A8_UINT, UINT}, |
| {VK_FORMAT_R16_UINT, UINT}, |
| {VK_FORMAT_R16G16_UINT, UINT}, |
| {VK_FORMAT_R16G16B16_UINT, UINT}, |
| {VK_FORMAT_R16G16B16A16_UINT, UINT}, |
| {VK_FORMAT_R32_UINT, UINT}, |
| {VK_FORMAT_R32G32_UINT, UINT}, |
| {VK_FORMAT_R32G32B32_UINT, UINT}, |
| {VK_FORMAT_R32G32B32A32_UINT, UINT}, |
| {VK_FORMAT_R64_UINT, UINT}, |
| {VK_FORMAT_R64G64_UINT, UINT}, |
| {VK_FORMAT_R64G64B64_UINT, UINT}, |
| {VK_FORMAT_R64G64B64A64_UINT, UINT}}); |
| |
| std::vector<struct TestFilterType> tests(2); |
| tests[0].err_msg = "VUID-vkCmdDraw-magFilter-04553"; |
| |
| tests[1].filter = VK_FILTER_CUBIC_IMG; |
| tests[1].required_format_feature = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG; |
| tests[1].err_msg = "VUID-vkCmdDraw-None-02692"; |
| |
| for (auto &test_struct : tests) { |
| for (std::pair<VkFormat, FormatTypes> cur_format_pair : formats_to_check) { |
| VkFormatProperties props = {}; |
| vk::GetPhysicalDeviceFormatProperties(Gpu(), cur_format_pair.first, &props); |
| if (test_struct.format == VK_FORMAT_UNDEFINED && props.linearTilingFeatures != 0 && |
| (props.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && |
| !(props.linearTilingFeatures & test_struct.required_format_feature)) { |
| test_struct.format = cur_format_pair.first; |
| test_struct.format_type = cur_format_pair.second; |
| } else if (test_struct.format == VK_FORMAT_UNDEFINED && props.optimalTilingFeatures != 0 && |
| (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && |
| !(props.optimalTilingFeatures & test_struct.required_format_feature)) { |
| test_struct.format = cur_format_pair.first; |
| test_struct.format_type = cur_format_pair.second; |
| test_struct.tiling = VK_IMAGE_TILING_OPTIMAL; |
| } |
| |
| if (test_struct.format != VK_FORMAT_UNDEFINED) { |
| break; |
| } |
| } |
| } |
| |
| const char bindStateFragiSamplerShaderText[] = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform isampler2D s; |
| layout(location=0) out vec4 x; |
| void main(){ |
| x = texture(s, vec2(1)); |
| } |
| )glsl"; |
| |
| const char bindStateFraguSamplerShaderText[] = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform usampler2D s; |
| layout(location=0) out vec4 x; |
| void main(){ |
| x = texture(s, vec2(1)); |
| } |
| )glsl"; |
| |
| InitRenderTarget(); |
| |
| for (const auto &test_struct : tests) { |
| if (test_struct.format == VK_FORMAT_UNDEFINED) { |
| printf("Could not find a testable format for filter %d. Skipping test for said filter.\n", test_struct.filter); |
| continue; |
| } |
| |
| VkSamplerCreateInfo sci = SafeSaneSamplerCreateInfo(); |
| |
| sci.magFilter = test_struct.filter; |
| sci.minFilter = test_struct.filter; |
| sci.compareEnable = VK_FALSE; |
| |
| if (test_struct.filter == VK_FILTER_CUBIC_IMG) { |
| if (cubic_support) { |
| sci.anisotropyEnable = VK_FALSE; |
| } else { |
| printf("VK_FILTER_CUBIC_IMG not supported. Skipping use of VK_FILTER_CUBIC_IMG this test.\n"); |
| continue; |
| } |
| } |
| |
| vkt::Sampler sampler(*m_device, sci); |
| auto image_ci = |
| vkt::Image::ImageCreateInfo2D(128, 128, 1, 1, test_struct.format, VK_IMAGE_USAGE_SAMPLED_BIT, test_struct.tiling); |
| vkt::Image mpimage(*m_device, image_ci); |
| vkt::ImageView view = mpimage.CreateView(); |
| |
| CreatePipelineHelper pipe(*this); |
| VkShaderObj *fs = nullptr; |
| |
| if (test_struct.format_type == FLOAT) { |
| fs = new VkShaderObj(this, kFragmentSamplerGlsl, VK_SHADER_STAGE_FRAGMENT_BIT); |
| } else if (test_struct.format_type == SINT) { |
| fs = new VkShaderObj(this, bindStateFragiSamplerShaderText, VK_SHADER_STAGE_FRAGMENT_BIT); |
| } else if (test_struct.format_type == UINT) { |
| fs = new VkShaderObj(this, bindStateFraguSamplerShaderText, VK_SHADER_STAGE_FRAGMENT_BIT); |
| } |
| |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs->GetStageCreateInfo()}; |
| pipe.dsl_bindings_ = { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }; |
| ASSERT_EQ(VK_SUCCESS, pipe.CreateGraphicsPipeline()); |
| |
| pipe.descriptor_set_->WriteDescriptorImageInfo(0, view, sampler.handle(), 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.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_.handle(), 0, 1, |
| &pipe.descriptor_set_->set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError(test_struct.err_msg.c_str()); |
| vk::CmdDraw(m_command_buffer.handle(), 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| delete fs; |
| } |
| } |
| |
| TEST_F(NegativeSampler, LinearReductionModeMinMax) { |
| AddRequiredExtensions(VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME); |
| 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 format = VK_FORMAT_R8G8B8A8_UNORM; |
| VkFormatProperties formatProps; |
| fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT(Gpu(), format, &formatProps); |
| formatProps.optimalTilingFeatures = (formatProps.optimalTilingFeatures & ~VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT); |
| formatProps.optimalTilingFeatures |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; |
| fpvkSetPhysicalDeviceFormatPropertiesEXT(Gpu(), format, formatProps); |
| |
| vkt::Image image(*m_device, 128, 128, 1, format, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::ImageView image_view = image.CreateView(); |
| |
| VkSamplerReductionModeCreateInfo reduction_mode_ci = vku::InitStructHelper(); |
| reduction_mode_ci.reductionMode = VK_SAMPLER_REDUCTION_MODE_MIN; |
| |
| VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo(); |
| sampler_ci.pNext = &reduction_mode_ci; |
| 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); |
| |
| char const *fs_source = R"glsl( |
| #version 450 |
| layout (set=0, binding=0) uniform sampler2D bad; |
| layout(location=0) out vec4 color; |
| void main() { |
| color = texture(bad, gl_FragCoord.xy); |
| } |
| )glsl"; |
| VkShaderObj fs(this, 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}, |
| }); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| descriptor_set.WriteDescriptorImageInfo(0, image_view, sampler.handle()); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_[1] = fs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout.handle(); |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1, |
| &descriptor_set.set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-magFilter-09598"); |
| vk::CmdDraw(m_command_buffer.handle(), 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeSampler, AddressModeWithCornerSampledNV) { |
| TEST_DESCRIPTION( |
| "Create image with VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV flag and sample it with something other than " |
| "VK_SAMPLER_ADDRESS_MODE_CLAMP_EDGE."); |
| |
| AddRequiredExtensions(VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitFramework()); |
| |
| RETURN_IF_SKIP(InitState(nullptr, nullptr, 0)); |
| InitRenderTarget(); |
| |
| VkImageCreateInfo image_info = vkt::Image::CreateInfo(); |
| image_info.flags = VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV; |
| image_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| // If flags contains VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV, |
| // imageType must be VK_IMAGE_TYPE_2D or VK_IMAGE_TYPE_3D |
| image_info.imageType = VK_IMAGE_TYPE_2D; |
| // If flags contains VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV and imageType is VK_IMAGE_TYPE_2D, |
| // extent.width and extent.height must be greater than 1. |
| image_info.extent = {2, 2, 1}; |
| image_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| |
| vkt::Image test_image(*m_device, image_info, vkt::set_layout); |
| |
| VkSamplerCreateInfo sci = SafeSaneSamplerCreateInfo(); |
| sci.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; |
| vkt::Sampler sampler(*m_device, sci); |
| |
| vkt::ImageView view = test_image.CreateView(); |
| |
| CreatePipelineHelper pipe(*this); |
| VkShaderObj fs(this, kFragmentSamplerGlsl, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.dsl_bindings_ = { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }; |
| pipe.CreateGraphicsPipeline(); |
| |
| pipe.descriptor_set_->WriteDescriptorImageInfo(0, view, sampler.handle(), 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.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_.handle(), 0, 1, |
| &pipe.descriptor_set_->set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-flags-02696"); |
| vk::CmdDraw(m_command_buffer.handle(), 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeSampler, MultiplaneImageSamplerConversionMismatch) { |
| TEST_DESCRIPTION( |
| "Create sampler with ycbcr conversion and use with an image created without ycrcb conversion or immutable sampler"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredFeature(vkt::Feature::samplerYcbcrConversion); |
| AddRequiredFeature(vkt::Feature::samplerAnisotropy); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(128, 128, 1, 1, VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| image_ci.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; // need for multi-planar |
| image_ci.tiling = VK_IMAGE_TILING_LINEAR; |
| |
| // Verify formats |
| bool supported = ImageFormatIsSupported(instance(), Gpu(), image_ci, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT); |
| if (!supported) { |
| GTEST_SKIP() << "Multiplane image format not supported"; |
| } |
| |
| if (!FormatFeaturesAreSupported(Gpu(), VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, VK_IMAGE_TILING_OPTIMAL, |
| VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) { |
| GTEST_SKIP() << "Required formats/features not supported"; |
| } |
| |
| // Create Ycbcr conversion |
| VkSamplerYcbcrConversionCreateInfo ycbcr_create_info = vku::InitStructHelper(); |
| ycbcr_create_info.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; |
| ycbcr_create_info.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; |
| ycbcr_create_info.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL; |
| ycbcr_create_info.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY}; |
| ycbcr_create_info.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN; |
| ycbcr_create_info.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN; |
| ycbcr_create_info.chromaFilter = VK_FILTER_NEAREST; |
| ycbcr_create_info.forceExplicitReconstruction = false; |
| vkt::SamplerYcbcrConversion conversions[2]; |
| conversions[0].init(*m_device, ycbcr_create_info); |
| ycbcr_create_info.components.a = VK_COMPONENT_SWIZZLE_ZERO; // Just anything different than above |
| conversions[1].init(*m_device, ycbcr_create_info); |
| |
| VkSamplerYcbcrConversionInfo ycbcr_info = vku::InitStructHelper(); |
| ycbcr_info.conversion = conversions[0].handle(); |
| |
| // Create a sampler using conversion |
| VkSamplerCreateInfo sci = SafeSaneSamplerCreateInfo(); |
| sci.pNext = &ycbcr_info; |
| // Create two samplers with two different conversions, such that one will mismatch |
| // It will make the second sampler fail to see if the log prints the second sampler or the first sampler. |
| vkt::Sampler samplers[2]; |
| samplers[0].init(*m_device, sci); |
| ycbcr_info.conversion = conversions[1].handle(); // Need two samplers with different conversions |
| samplers[1].init(*m_device, sci); |
| |
| vkt::Sampler BadSampler; |
| sci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; |
| m_errorMonitor->SetDesiredError("VUID-VkSamplerCreateInfo-addressModeU-01646"); |
| BadSampler.init(*m_device, sci); |
| m_errorMonitor->VerifyFound(); |
| |
| sci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; |
| sci.unnormalizedCoordinates = VK_TRUE; |
| sci.minLod = 0.0; |
| sci.maxLod = 0.0; |
| m_errorMonitor->SetDesiredError("VUID-VkSamplerCreateInfo-addressModeU-01646"); |
| BadSampler.init(*m_device, sci); |
| m_errorMonitor->VerifyFound(); |
| |
| { |
| // samplerAnisotropy |
| sci.unnormalizedCoordinates = VK_FALSE; |
| sci.anisotropyEnable = VK_TRUE; |
| m_errorMonitor->SetDesiredError("VUID-VkSamplerCreateInfo-addressModeU-01646"); |
| BadSampler.init(*m_device, sci); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Create an image without a Ycbcr conversion |
| vkt::Image mpimage(*m_device, image_ci, vkt::set_layout); |
| ycbcr_info.conversion = conversions[0].handle(); // Need two samplers with different conversions |
| vkt::ImageView view = mpimage.CreateView(VK_IMAGE_ASPECT_PLANE_0_BIT, &ycbcr_info); |
| |
| VkSampler vksamplers[2] = {samplers[0].handle(), samplers[1].handle()}; |
| // Use the image and sampler together in a descriptor set |
| OneOffDescriptorSet descriptor_set(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, VK_SHADER_STAGE_ALL, vksamplers}, |
| }); |
| |
| if (!descriptor_set.set_) { |
| GTEST_SKIP() << "Failed to allocate descriptor set, skipping test."; |
| } |
| |
| // Use the same image view twice, using the same sampler, with the *second* mismatched with the *second* immutable sampler |
| VkDescriptorImageInfo image_infos[2]; |
| image_infos[0] = {}; |
| image_infos[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
| image_infos[0].imageView = view.handle(); |
| image_infos[0].sampler = samplers[0].handle(); |
| image_infos[1] = image_infos[0]; |
| |
| // Update the descriptor set expecting to get an error |
| VkWriteDescriptorSet descriptor_write = vku::InitStructHelper(); |
| descriptor_write.dstSet = descriptor_set.set_; |
| descriptor_write.dstBinding = 0; |
| descriptor_write.descriptorCount = 2; |
| descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; |
| descriptor_write.pImageInfo = image_infos; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-01948"); |
| vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL); |
| m_errorMonitor->VerifyFound(); |
| |
| // pImmutableSamplers = nullptr causes an error , VUID-VkWriteDescriptorSet-descriptorType-02738. |
| // Because if pNext chains a VkSamplerYcbcrConversionInfo, the sampler has to be a immutable sampler. |
| OneOffDescriptorSet descriptor_set_1947(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| descriptor_write.dstSet = descriptor_set_1947.set_; |
| descriptor_write.descriptorCount = 1; |
| descriptor_write.pImageInfo = &image_infos[0]; |
| m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-02738"); |
| vk::UpdateDescriptorSets(device(), 1, &descriptor_write, 0, NULL); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeSampler, ImageSamplerConversionNullImageView) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::samplerYcbcrConversion); |
| AddRequiredFeature(vkt::Feature::nullDescriptor); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(128, 128, 1, 1, VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| image_ci.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; // need for multi-planar |
| image_ci.tiling = VK_IMAGE_TILING_LINEAR; |
| if (!ImageFormatIsSupported(instance(), Gpu(), image_ci, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { |
| GTEST_SKIP() << "Multiplane image format not supported"; |
| } |
| if (!FormatFeaturesAreSupported(Gpu(), VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, VK_IMAGE_TILING_OPTIMAL, |
| VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) { |
| GTEST_SKIP() << "Required formats/features not supported"; |
| } |
| |
| vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8R8_2PLANE_420_UNORM); |
| VkSamplerYcbcrConversionInfo ycbcr_info = vku::InitStructHelper(); |
| ycbcr_info.conversion = conversion.handle(); |
| VkSamplerCreateInfo sci = SafeSaneSamplerCreateInfo(); |
| sci.pNext = &ycbcr_info; |
| vkt::Sampler sampler(*m_device, sci); |
| |
| OneOffDescriptorSet descriptor_set( |
| m_device, { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler.handle()}, |
| }); |
| if (!descriptor_set.set_) { |
| GTEST_SKIP() << "Failed to allocate descriptor set, skipping test."; |
| } |
| descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler.handle()); |
| |
| m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-09506"); |
| descriptor_set.UpdateDescriptorSets(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeSampler, FilterMinmax) { |
| TEST_DESCRIPTION("Invalid uses of VK_EXT_sampler_filter_minmax."); |
| AddRequiredExtensions(VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::samplerYcbcrConversion); |
| RETURN_IF_SKIP(Init()); |
| |
| if (!FormatFeaturesAreSupported(Gpu(), VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, VK_IMAGE_TILING_OPTIMAL, |
| VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) { |
| GTEST_SKIP() << "Required formats/features not supported"; |
| } |
| |
| // Create Ycbcr conversion |
| VkSamplerYcbcrConversionCreateInfo ycbcr_create_info = vku::InitStructHelper(); |
| ycbcr_create_info.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; |
| ycbcr_create_info.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; |
| ycbcr_create_info.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL; |
| ycbcr_create_info.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY}; |
| ycbcr_create_info.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN; |
| ycbcr_create_info.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN; |
| ycbcr_create_info.chromaFilter = VK_FILTER_NEAREST; |
| ycbcr_create_info.forceExplicitReconstruction = false; |
| |
| VkSamplerYcbcrConversion conversion; |
| vk::CreateSamplerYcbcrConversionKHR(m_device->handle(), &ycbcr_create_info, nullptr, &conversion); |
| |
| VkSamplerYcbcrConversionInfo ycbcr_info = vku::InitStructHelper(); |
| ycbcr_info.conversion = conversion; |
| |
| VkSamplerReductionModeCreateInfo reduction_info = vku::InitStructHelper(); |
| reduction_info.reductionMode = VK_SAMPLER_REDUCTION_MODE_MIN; |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.pNext = &reduction_info; |
| |
| // Wrong mode with a YCbCr Conversion used |
| reduction_info.pNext = &ycbcr_info; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-None-01647"); |
| |
| // Wrong mode with compareEnable |
| reduction_info.pNext = nullptr; |
| sampler_info.compareEnable = VK_TRUE; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-compareEnable-01423"); |
| |
| vk::DestroySamplerYcbcrConversionKHR(m_device->handle(), conversion, nullptr); |
| } |
| |
| TEST_F(NegativeSampler, CustomBorderColor) { |
| TEST_DESCRIPTION("Tests for VUs for VK_EXT_custom_border_color"); |
| AddRequiredExtensions(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::customBorderColors); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.borderColor = VK_BORDER_COLOR_INT_CUSTOM_EXT; |
| // No SCBCCreateInfo in pNext |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-borderColor-04011"); |
| |
| VkSamplerCustomBorderColorCreateInfoEXT custom_color_cinfo = vku::InitStructHelper(); |
| custom_color_cinfo.format = VK_FORMAT_R32_SFLOAT; |
| sampler_info.pNext = &custom_color_cinfo; |
| // Format mismatch |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCustomBorderColorCreateInfoEXT-format-07605"); |
| |
| custom_color_cinfo.format = VK_FORMAT_UNDEFINED; |
| // Format undefined with no customBorderColorWithoutFormat |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCustomBorderColorCreateInfoEXT-format-04014"); |
| |
| custom_color_cinfo.format = VK_FORMAT_R8G8B8A8_UINT; |
| vkt::Sampler sampler(*m_device, sampler_info); |
| |
| VkDescriptorSetLayoutBinding dsl_binding = {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler.handle()}; |
| VkDescriptorSetLayoutCreateInfo ds_layout_ci = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL, 0, 1, &dsl_binding}; |
| VkDescriptorSetLayout ds_layout; |
| m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-pImmutableSamplers-04009"); |
| vk::CreateDescriptorSetLayout(device(), &ds_layout_ci, NULL, &ds_layout); |
| m_errorMonitor->VerifyFound(); |
| |
| VkPhysicalDeviceCustomBorderColorPropertiesEXT custom_properties = vku::InitStructHelper(); |
| auto prop2 = GetPhysicalDeviceProperties2(custom_properties); |
| |
| if ((custom_properties.maxCustomBorderColorSamplers <= 0xFFFF) && |
| (prop2.properties.limits.maxSamplerAllocationCount >= custom_properties.maxCustomBorderColorSamplers)) { |
| VkSampler samplers[0xFFFF]; |
| // Still have one custom border color sampler from above, so this should exceed max |
| m_errorMonitor->SetDesiredError("VUID-VkSamplerCreateInfo-None-04012"); |
| if (prop2.properties.limits.maxSamplerAllocationCount <= custom_properties.maxCustomBorderColorSamplers) { |
| m_errorMonitor->SetDesiredError("VUID-vkCreateSampler-maxSamplerAllocationCount-04110"); |
| } |
| for (uint32_t i = 0; i < custom_properties.maxCustomBorderColorSamplers; i++) { |
| vk::CreateSampler(device(), &sampler_info, NULL, &samplers[i]); |
| } |
| m_errorMonitor->VerifyFound(); |
| for (uint32_t i = 0; i < custom_properties.maxCustomBorderColorSamplers - 1; i++) { |
| vk::DestroySampler(device(), samplers[i], nullptr); |
| } |
| } |
| } |
| |
| TEST_F(NegativeSampler, CustomBorderColorFormatUndefined) { |
| TEST_DESCRIPTION("Tests for VUID-VkSamplerCustomBorderColorCreateInfoEXT-format-04015"); |
| AddRequiredExtensions(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::customBorderColors); |
| AddRequiredFeature(vkt::Feature::customBorderColorWithoutFormat); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.borderColor = VK_BORDER_COLOR_INT_CUSTOM_EXT; |
| VkSamplerCustomBorderColorCreateInfoEXT custom_color_cinfo = vku::InitStructHelper(); |
| custom_color_cinfo.format = VK_FORMAT_UNDEFINED; |
| sampler_info.pNext = &custom_color_cinfo; |
| vkt::Sampler sampler(*m_device, sampler_info); |
| |
| vkt::Image image(*m_device, 32, 32, 1, VK_FORMAT_B4G4R4A4_UNORM_PACK16, VK_IMAGE_USAGE_SAMPLED_BIT); |
| image.Layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| OneOffDescriptorSet descriptor_set(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| auto image_view_create_info = image.BasicViewCreatInfo(); |
| vkt::ImageView view(*m_device, image_view_create_info); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, view, sampler); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| char const *fsSource = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform sampler2D s; |
| layout(location=0) out vec4 x; |
| void main(){ |
| x = texture(s, vec2(1)); |
| } |
| )glsl"; |
| VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_[1] = fs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout.handle(); |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1, |
| &descriptor_set.set_, 0, NULL); |
| m_errorMonitor->SetDesiredError("VUID-VkSamplerCustomBorderColorCreateInfoEXT-format-04015"); |
| vk::CmdDraw(m_command_buffer.handle(), 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeSampler, CustomBorderColorFormatUndefinedNonCombined) { |
| AddRequiredExtensions(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::customBorderColors); |
| AddRequiredFeature(vkt::Feature::customBorderColorWithoutFormat); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.borderColor = VK_BORDER_COLOR_INT_CUSTOM_EXT; |
| VkSamplerCustomBorderColorCreateInfoEXT custom_color_cinfo = vku::InitStructHelper(); |
| custom_color_cinfo.format = VK_FORMAT_UNDEFINED; |
| sampler_info.pNext = &custom_color_cinfo; |
| vkt::Sampler sampler(*m_device, sampler_info); |
| |
| vkt::Image image(*m_device, 32, 32, 1, VK_FORMAT_B4G4R4A4_UNORM_PACK16, VK_IMAGE_USAGE_SAMPLED_BIT); |
| image.Layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| OneOffDescriptorSet descriptor_set(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| auto image_view_create_info = image.BasicViewCreatInfo(); |
| vkt::ImageView image_view(*m_device, image_view_create_info); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER); |
| descriptor_set.WriteDescriptorImageInfo(1, image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| char const *fsSource = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform sampler s; |
| layout(set=0, binding=1) uniform texture2D t; |
| layout(location=0) out vec4 x; |
| void main(){ |
| x = texture(sampler2D(t, s), vec2(1.0)); |
| } |
| )glsl"; |
| VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_[1] = fs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout.handle(); |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1, |
| &descriptor_set.set_, 0, NULL); |
| m_errorMonitor->SetDesiredError("VUID-VkSamplerCustomBorderColorCreateInfoEXT-format-04015"); |
| vk::CmdDraw(m_command_buffer.handle(), 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| // TODO - https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8922 |
| // we currently only check the same descriptor set for the sampler pair |
| TEST_F(NegativeSampler, DISABLED_CustomBorderColorFormatUndefinedNonCombinedMultipleSets) { |
| AddRequiredExtensions(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::customBorderColors); |
| AddRequiredFeature(vkt::Feature::customBorderColorWithoutFormat); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.borderColor = VK_BORDER_COLOR_INT_CUSTOM_EXT; |
| VkSamplerCustomBorderColorCreateInfoEXT custom_color_cinfo = vku::InitStructHelper(); |
| custom_color_cinfo.format = VK_FORMAT_UNDEFINED; |
| sampler_info.pNext = &custom_color_cinfo; |
| vkt::Sampler sampler(*m_device, sampler_info); |
| |
| vkt::Image image(*m_device, 32, 32, 1, VK_FORMAT_B4G4R4A4_UNORM_PACK16, VK_IMAGE_USAGE_SAMPLED_BIT); |
| image.Layout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| OneOffDescriptorSet descriptor_set0(m_device, { |
| {2, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| OneOffDescriptorSet descriptor_set1(m_device, { |
| {3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set0.layout_, &descriptor_set1.layout_}); |
| auto image_view_create_info = image.BasicViewCreatInfo(); |
| vkt::ImageView image_view(*m_device, image_view_create_info); |
| |
| descriptor_set0.WriteDescriptorImageInfo(2, VK_NULL_HANDLE, sampler, VK_DESCRIPTOR_TYPE_SAMPLER); |
| descriptor_set0.UpdateDescriptorSets(); |
| descriptor_set1.WriteDescriptorImageInfo(3, image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| descriptor_set1.UpdateDescriptorSets(); |
| |
| char const *fsSource = R"glsl( |
| #version 450 |
| layout(set=0, binding=2) uniform sampler s; |
| layout(set=1, binding=3) uniform texture2D t; |
| layout(location=0) out vec4 x; |
| void main(){ |
| x = texture(sampler2D(t, s), vec2(1.0)); |
| } |
| )glsl"; |
| VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_[1] = fs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout.handle(); |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1, |
| &descriptor_set0.set_, 0, NULL); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 1, 1, |
| &descriptor_set1.set_, 0, NULL); |
| m_errorMonitor->SetDesiredError("VUID-VkSamplerCustomBorderColorCreateInfoEXT-format-04015"); |
| vk::CmdDraw(m_command_buffer.handle(), 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeSampler, UnnormalizedCoordinatesCombinedSampler) { |
| TEST_DESCRIPTION( |
| "If a samper is unnormalizedCoordinates, the imageview has to be some specific types. Uses COMBINED_IMAGE_SAMPLER"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| // This generates OpImage*Dref* instruction on R8G8B8A8_UNORM format. |
| // Verify that it is allowed on this implementation if |
| // VK_KHR_format_feature_flags2 is available. |
| if (DeviceExtensionSupported(Gpu(), nullptr, VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME)) { |
| VkFormatProperties3KHR fmt_props_3 = vku::InitStructHelper(); |
| VkFormatProperties2 fmt_props = vku::InitStructHelper(&fmt_props_3); |
| |
| vk::GetPhysicalDeviceFormatProperties2(Gpu(), VK_FORMAT_R8G8B8A8_UNORM, &fmt_props); |
| |
| if (!(fmt_props_3.optimalTilingFeatures & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT)) { |
| GTEST_SKIP() << "R8G8B8A8_UNORM does not support OpImage*Dref* operations"; |
| } |
| } |
| |
| VkShaderObj vs(this, kMinimalShaderGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| const char fsSource[] = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) uniform sampler3D image_view_3d; |
| layout (set = 0, binding = 1) uniform sampler2D tex; |
| layout (set = 0, binding = 2) uniform sampler2DShadow tex_dep; |
| void main() { |
| // VUID 08609 |
| // 3D Image View is used with unnormalized coordinates |
| // Also is VUID 08610 but the invalid image view is reported first |
| vec4 x = texture(image_view_3d, vec3(0)); |
| |
| // VUID 08610 |
| // OpImageSampleDrefImplicitLod is used with unnormalized coordinates |
| float f = texture(tex_dep, vec3(0)); |
| |
| // VUID 08611 |
| // OpImageSampleExplicitLod instructions that incudes a offset with unnormalized coordinates |
| x = textureLodOffset(tex, vec2(0), 0, ivec2(0)); |
| } |
| )glsl"; |
| VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| CreatePipelineHelper g_pipe(*this); |
| g_pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| g_pipe.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL_GRAPHICS, nullptr}, |
| {2, 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(); |
| |
| image_ci.imageType = VK_IMAGE_TYPE_3D; |
| vkt::Image image_3d(*m_device, image_ci, vkt::set_layout); |
| |
| // If the sampler is unnormalizedCoordinates, the imageview type shouldn't be 3D, CUBE, 1D_ARRAY, 2D_ARRAY, CUBE_ARRAY. |
| // This causes DesiredFailure. |
| vkt::ImageView view_fail = image_3d.CreateView(VK_IMAGE_VIEW_TYPE_3D); |
| |
| 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_fail, sampler.handle(), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(1, view_pass, sampler.handle(), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(2, view_pass, sampler.handle(), 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.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1, |
| &g_pipe.descriptor_set_->set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08609"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08610"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08611"); |
| vk::CmdDraw(m_command_buffer.handle(), 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeSampler, UnnormalizedCoordinatesSeparateSampler) { |
| TEST_DESCRIPTION( |
| "If a samper is unnormalizedCoordinates, the imageview has to be some specific types. Doesn't use COMBINED_IMAGE_SAMPLER"); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| // This generates OpImage*Dref* instruction on R8G8B8A8_UNORM format. |
| // Verify that it is allowed on this implementation if |
| // VK_KHR_format_feature_flags2 is available. |
| if (DeviceExtensionSupported(Gpu(), nullptr, VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME)) { |
| VkFormatProperties3KHR fmt_props_3 = vku::InitStructHelper(); |
| VkFormatProperties2 fmt_props = vku::InitStructHelper(&fmt_props_3); |
| |
| vk::GetPhysicalDeviceFormatProperties2(Gpu(), VK_FORMAT_R8G8B8A8_UNORM, &fmt_props); |
| |
| if (!(fmt_props_3.optimalTilingFeatures & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT)) { |
| GTEST_SKIP() << "R8G8B8A8_UNORM does not support OpImage*Dref* operations"; |
| } |
| } |
| |
| VkShaderObj vs(this, kMinimalShaderGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| const char fsSource[] = R"glsl( |
| #version 450 |
| // VK_DESCRIPTOR_TYPE_SAMPLER |
| layout(set = 0, binding = 0) uniform sampler s1; |
| layout(set = 0, binding = 1) uniform sampler s2; |
| // VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE |
| layout(set = 0, binding = 2) uniform texture2D si_good; |
| layout(set = 0, binding = 3) uniform texture2D si_good_2; |
| layout(set = 0, binding = 4) uniform texture3D si_bad; // 3D image view |
| |
| void main() { |
| // VUID 08609 |
| // 3D Image View is used with unnormalized coordinates |
| // Also is VUID 08610 but the invalid image view is reported first |
| vec4 x = texture(sampler3D(si_bad, s1), vec3(0)); |
| |
| // VUID 08610 |
| // OpImageSampleImplicitLod is used with unnormalized coordinates |
| x = texture(sampler2D(si_good, s1), vec2(0)); |
| |
| // VUID 08611 |
| // OpImageSampleExplicitLod instructions that incudes a offset with unnormalized coordinates |
| x = textureLodOffset(sampler2D(si_good_2, s2), vec2(0), 0, ivec2(0)); |
| } |
| )glsl"; |
| VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| CreatePipelineHelper g_pipe(*this); |
| g_pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| g_pipe.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 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_a = image.CreateView(); |
| vkt::ImageView view_pass_b = image.CreateView(); |
| |
| image_ci.imageType = VK_IMAGE_TYPE_3D; |
| vkt::Image image_3d(*m_device, image_ci, vkt::set_layout); |
| |
| // If the sampler is unnormalizedCoordinates, the imageview type shouldn't be 3D, CUBE, 1D_ARRAY, 2D_ARRAY, CUBE_ARRAY. |
| // This causes DesiredFailure. |
| vkt::ImageView view_fail = image_3d.CreateView(VK_IMAGE_VIEW_TYPE_3D); |
| |
| // Need 2 samplers (and ImageView) because testing both VUID and it will tie both errors to the same sampler/imageView, but only |
| // 08610 will be triggered since it's first in the validation code |
| VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo(); |
| sampler_ci.unnormalizedCoordinates = VK_TRUE; |
| sampler_ci.maxLod = 0; |
| vkt::Sampler sampler_a(*m_device, sampler_ci); |
| vkt::Sampler sampler_b(*m_device, sampler_ci); |
| |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler_a.handle(), VK_DESCRIPTOR_TYPE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(1, VK_NULL_HANDLE, sampler_b.handle(), VK_DESCRIPTOR_TYPE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(2, view_pass_a, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(3, view_pass_b, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(4, view_fail, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, |
| 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.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1, |
| &g_pipe.descriptor_set_->set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08609"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08610"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08611"); |
| vk::CmdDraw(m_command_buffer.handle(), 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeSampler, UnnormalizedCoordinatesSeparateSamplerSharedImage) { |
| TEST_DESCRIPTION("Doesn't use COMBINED_IMAGE_SAMPLER, but multiple OpLoad share Image OpVariable"); |
| |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkShaderObj vs(this, kMinimalShaderGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| // There are 2 OpLoad/OpAccessChain that point the same OpVariable |
| const char fsSource[] = R"glsl( |
| #version 450 |
| // VK_DESCRIPTOR_TYPE_SAMPLER |
| layout(set = 0, binding = 0) uniform sampler s_good; // unnormalized |
| layout(set = 0, binding = 1) uniform sampler s_bad; // unnormalized |
| // VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE |
| layout(set = 0, binding = 2) uniform texture2D si_good; |
| |
| void main() { |
| vec4 x = texture(sampler2D(si_good, s_good), vec2(0)); |
| vec4 y = texture(sampler2D(si_good, s_bad), vec2(0)); |
| } |
| )glsl"; |
| VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| CreatePipelineHelper g_pipe(*this); |
| g_pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| g_pipe.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}}; |
| g_pipe.CreateGraphicsPipeline(); |
| |
| const VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; |
| const 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 image_view = image.CreateView(); |
| |
| VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo(); |
| sampler_ci.unnormalizedCoordinates = VK_FALSE; |
| sampler_ci.maxLod = 0; |
| vkt::Sampler sampler_good(*m_device, sampler_ci); |
| sampler_ci.unnormalizedCoordinates = VK_TRUE; |
| vkt::Sampler sampler_bad(*m_device, sampler_ci); |
| |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler_good.handle(), VK_DESCRIPTOR_TYPE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(1, VK_NULL_HANDLE, sampler_bad.handle(), VK_DESCRIPTOR_TYPE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(2, image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| g_pipe.descriptor_set_->UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1, |
| &g_pipe.descriptor_set_->set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08610"); |
| vk::CmdDraw(m_command_buffer.handle(), 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeSampler, UnnormalizedCoordinatesSeparateSamplerSharedSampler) { |
| TEST_DESCRIPTION("Doesn't use COMBINED_IMAGE_SAMPLER, but multiple OpLoad share Sampler OpVariable"); |
| |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkShaderObj vs(this, kMinimalShaderGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| // There are 2 OpLoad/OpAccessChain that point the same OpVariable |
| const char fsSource[] = R"glsl( |
| #version 450 |
| // VK_DESCRIPTOR_TYPE_SAMPLER |
| layout(set = 0, binding = 0) uniform sampler s1; |
| // VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE |
| layout(set = 0, binding = 1) uniform texture2D si_good; |
| layout(set = 0, binding = 2) uniform texture3D si_bad; // 3D image view |
| |
| void main() { |
| vec4 x = texture(sampler2D(si_good, s1), vec2(0)); |
| vec4 y = texture(sampler3D(si_bad, s1), vec3(0)); |
| } |
| )glsl"; |
| VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| CreatePipelineHelper g_pipe(*this); |
| g_pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| g_pipe.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}}; |
| g_pipe.CreateGraphicsPipeline(); |
| |
| const VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; |
| const 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 image_view = image.CreateView(); |
| |
| image_ci.imageType = VK_IMAGE_TYPE_3D; |
| vkt::Image image_3d(*m_device, image_ci, vkt::set_layout); |
| vkt::ImageView image_view_3d = image_3d.CreateView(VK_IMAGE_VIEW_TYPE_3D); |
| |
| 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, VK_NULL_HANDLE, sampler.handle(), VK_DESCRIPTOR_TYPE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(1, image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(2, image_view_3d, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, |
| 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.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1, |
| &g_pipe.descriptor_set_->set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08609"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08610"); |
| vk::CmdDraw(m_command_buffer.handle(), 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeSampler, UnnormalizedCoordinatesSeparateSamplerSharedSamplerArray) { |
| TEST_DESCRIPTION("Doesn't use COMBINED_IMAGE_SAMPLER, but multiple OpLoad share Sampler OpVariable"); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| // There are 2 OpLoad/OpAccessChain that point the same OpVariable |
| const char fsSource[] = R"glsl( |
| #version 450 |
| // VK_DESCRIPTOR_TYPE_SAMPLER |
| layout(set = 0, binding = 0) uniform sampler s1; |
| // VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE |
| layout(set = 0, binding = 1) uniform texture2D si_good; |
| layout(set = 0, binding = 2) uniform texture3D si_bad[2]; // 3D image view |
| layout(location=0) out vec4 color; |
| void main() { |
| vec4 x = texture(sampler2D(si_good, s1), vec2(0)); |
| vec4 y = texture(sampler3D(si_bad[1], s1), vec3(0)); |
| color = vec4(x + y); |
| } |
| )glsl"; |
| VkShaderObj vs(this, kVertexDrawPassthroughGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}}); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| CreatePipelineHelper g_pipe(*this); |
| g_pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| g_pipe.gp_ci_.layout = pipeline_layout.handle(); |
| g_pipe.CreateGraphicsPipeline(); |
| |
| const VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; |
| const 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 image_view = image.CreateView(); |
| |
| image_ci.imageType = VK_IMAGE_TYPE_3D; |
| vkt::Image image_3d(*m_device, image_ci, vkt::set_layout); |
| vkt::ImageView image_view_3d = image_3d.CreateView(VK_IMAGE_VIEW_TYPE_3D); |
| |
| VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo(); |
| sampler_ci.unnormalizedCoordinates = VK_TRUE; |
| sampler_ci.maxLod = 0; |
| vkt::Sampler sampler(*m_device, sampler_ci); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler.handle(), VK_DESCRIPTOR_TYPE_SAMPLER); |
| descriptor_set.WriteDescriptorImageInfo(1, image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| descriptor_set.WriteDescriptorImageInfo(2, image_view_3d, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| descriptor_set.WriteDescriptorImageInfo(2, image_view_3d, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, |
| 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.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1, |
| &descriptor_set.set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08609"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08610"); |
| vk::CmdDraw(m_command_buffer.handle(), 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeSampler, UnnormalizedCoordinatesInBoundsAccess) { |
| TEST_DESCRIPTION("If a samper is unnormalizedCoordinates, but using OpInBoundsAccessChain"); |
| |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkShaderObj vs(this, kMinimalShaderGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| // layout (set = 0, binding = 0) uniform sampler2D tex[2]; |
| // void main() { |
| // vec4 x = textureLodOffset(tex[1], vec2(0), 0, ivec2(0)); |
| // } |
| // |
| // but with OpInBoundsAccessChain instead of normal generated OpAccessChain |
| const char *fsSource = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" |
| OpExecutionMode %main OriginUpperLeft |
| OpSource GLSL 450 |
| OpDecorate %tex DescriptorSet 0 |
| OpDecorate %tex Binding 0 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %v4float = OpTypeVector %float 4 |
| %ptr_v4float = OpTypePointer Function %v4float |
| %10 = OpTypeImage %float 2D 0 0 0 1 Unknown |
| %11 = OpTypeSampledImage %10 |
| %uint = OpTypeInt 32 0 |
| %uint_2 = OpConstant %uint 2 |
| %array = OpTypeArray %11 %uint_2 |
| %ptr_uc_array = OpTypePointer UniformConstant %array |
| %tex = OpVariable %ptr_uc_array UniformConstant |
| %int = OpTypeInt 32 1 |
| %int_1 = OpConstant %int 1 |
| %ptr_uc = OpTypePointer UniformConstant %11 |
| %v2float = OpTypeVector %float 2 |
| %float_0 = OpConstant %float 0 |
| %24 = OpConstantComposite %v2float %float_0 %float_0 |
| %v2int = OpTypeVector %int 2 |
| %int_0 = OpConstant %int 0 |
| %27 = OpConstantComposite %v2int %int_0 %int_0 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| %x = OpVariable %ptr_v4float Function |
| %20 = OpInBoundsAccessChain %ptr_uc %tex %int_1 |
| %21 = OpLoad %11 %20 |
| %28 = OpImageSampleExplicitLod %v4float %21 %24 Lod|ConstOffset %float_0 %27 |
| OpStore %x %28 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| |
| CreatePipelineHelper g_pipe(*this); |
| g_pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| g_pipe.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, 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(); |
| |
| image_ci.imageType = VK_IMAGE_TYPE_3D; |
| vkt::Image image_3d(*m_device, image_ci, vkt::set_layout); |
| |
| 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.handle(), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); |
| g_pipe.descriptor_set_->WriteDescriptorImageInfo(0, view_pass, sampler.handle(), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1); |
| g_pipe.descriptor_set_->UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1, |
| &g_pipe.descriptor_set_->set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08611"); |
| vk::CmdDraw(m_command_buffer.handle(), 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeSampler, UnnormalizedCoordinatesCopyObject) { |
| TEST_DESCRIPTION("If a samper is unnormalizedCoordinates, but using OpCopyObject"); |
| |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkShaderObj vs(this, kMinimalShaderGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| // layout (set = 0, binding = 0) uniform sampler2D tex; |
| // void main() { |
| // vec4 x = textureLodOffset(tex, vec2(0), 0, ivec2(0)); |
| // } |
| const char *fsSource = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" |
| OpExecutionMode %main OriginUpperLeft |
| OpSource GLSL 450 |
| OpDecorate %tex DescriptorSet 0 |
| OpDecorate %tex Binding 0 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %v4float = OpTypeVector %float 4 |
| %ptr_v4float = OpTypePointer Function %v4float |
| %10 = OpTypeImage %float 2D 0 0 0 1 Unknown |
| %11 = OpTypeSampledImage %10 |
| %uint = OpTypeInt 32 0 |
| %ptr_uc = OpTypePointer UniformConstant %11 |
| %tex = OpVariable %ptr_uc UniformConstant |
| %int = OpTypeInt 32 1 |
| %int_1 = OpConstant %int 1 |
| %v2float = OpTypeVector %float 2 |
| %float_0 = OpConstant %float 0 |
| %24 = OpConstantComposite %v2float %float_0 %float_0 |
| %v2int = OpTypeVector %int 2 |
| %int_0 = OpConstant %int 0 |
| %27 = OpConstantComposite %v2int %int_0 %int_0 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| %x = OpVariable %ptr_v4float Function |
| %var_copy = OpCopyObject %ptr_v4float %x |
| %14 = OpLoad %11 %tex |
| %load_copy = OpCopyObject %11 %14 |
| %22 = OpImageSampleExplicitLod %v4float %load_copy %24 Lod|ConstOffset %float_0 %27 |
| %image_copy = OpCopyObject %v4float %22 |
| OpStore %var_copy %image_copy |
| OpReturn |
| OpFunctionEnd |
| )"; |
| VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| |
| CreatePipelineHelper g_pipe(*this); |
| g_pipe.shader_stages_ = {g_pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| g_pipe.dsl_bindings_ = {{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.handle(), 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.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1, |
| &g_pipe.descriptor_set_->set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08611"); |
| vk::CmdDraw(m_command_buffer.handle(), 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeSampler, UnnormalizedCoordinatesLevelCount) { |
| TEST_DESCRIPTION("If a samper is unnormalizedCoordinates, the imageview has to have a LevelCount of 1"); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| const char fsSource[] = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) uniform sampler2D tex; |
| void main() { |
| vec4 color = texture(tex, vec2(0)); |
| } |
| )glsl"; |
| VkShaderObj fs(this, 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, 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); |
| image_ci.mipLevels = 2; |
| vkt::Image image(*m_device, image_ci, vkt::set_layout); |
| vkt::ImageView image_view = 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, image_view, sampler.handle(), 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.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.Handle()); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.pipeline_layout_.handle(), 0, 1, |
| &g_pipe.descriptor_set_->set_, 0, nullptr); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-unnormalizedCoordinates-09635"); |
| vk::CmdDraw(m_command_buffer.handle(), 1, 0, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeSampler, ShareOpSampledImage) { |
| TEST_DESCRIPTION( |
| "Have two OpImageSampleImplicitLod share the same OpSampledImage. This needs to be in the same block post-shader " |
| "instrumentation."); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| // #version 450 |
| // layout(set = 0, binding = 0) uniform sampler s1; |
| // layout(set = 0, binding = 1) uniform texture2D si_good; |
| // layout(location=0) out vec4 color; |
| // void main() { |
| // color = texture(sampler2D(si_good, s1), vec2(0)); |
| // color += texture(sampler2D(si_good, s1), vec2(color.x)); |
| // } |
| const char *fsSource = R"( |
| OpCapability Shader |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" %color |
| OpExecutionMode %main OriginUpperLeft |
| OpDecorate %color Location 0 |
| OpDecorate %si_good DescriptorSet 0 |
| OpDecorate %si_good Binding 1 |
| OpDecorate %s1 DescriptorSet 0 |
| OpDecorate %s1 Binding 0 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %v4float = OpTypeVector %float 4 |
| %_ptr_Output_v4float = OpTypePointer Output %v4float |
| %color = OpVariable %_ptr_Output_v4float Output |
| %10 = OpTypeImage %float 2D 0 0 0 1 Unknown |
| %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10 |
| %si_good = OpVariable %_ptr_UniformConstant_10 UniformConstant |
| %14 = OpTypeSampler |
| %_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 |
| %s1 = OpVariable %_ptr_UniformConstant_14 UniformConstant |
| %18 = OpTypeSampledImage %10 |
| %v2float = OpTypeVector %float 2 |
| %float_0 = OpConstant %float 0 |
| %22 = OpConstantComposite %v2float %float_0 %float_0 |
| %uint = OpTypeInt 32 0 |
| %uint_0 = OpConstant %uint 0 |
| %_ptr_Output_float = OpTypePointer Output %float |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| %13 = OpLoad %10 %si_good |
| %17 = OpLoad %14 %s1 |
| ; the results (%19) needs to be in same block as what consumes it |
| %19 = OpSampledImage %18 %13 %17 |
| %23 = OpImageSampleImplicitLod %v4float %19 %22 |
| OpStore %color %23 |
| %30 = OpAccessChain %_ptr_Output_float %color %uint_0 |
| %31 = OpLoad %float %30 |
| %32 = OpCompositeConstruct %v2float %31 %31 |
| %33 = OpImageSampleImplicitLod %v4float %19 %32 |
| %34 = OpLoad %v4float %color |
| %35 = OpFAdd %v4float %34 %33 |
| OpStore %color %35 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| VkShaderObj vs(this, kVertexDrawPassthroughGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| |
| OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}}); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| CreatePipelineHelper g_pipe(*this); |
| g_pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| g_pipe.gp_ci_.layout = pipeline_layout.handle(); |
| g_pipe.CreateGraphicsPipeline(); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D( |
| 128, 128, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::Image image(*m_device, image_ci, vkt::set_layout); |
| vkt::ImageView image_view = image.CreateView(); |
| |
| VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo(); |
| sampler_ci.unnormalizedCoordinates = VK_TRUE; |
| sampler_ci.maxLod = 0; |
| vkt::Sampler sampler(*m_device, sampler_ci); |
| |
| descriptor_set.WriteDescriptorImageInfo(0, VK_NULL_HANDLE, sampler.handle(), VK_DESCRIPTOR_TYPE_SAMPLER); |
| descriptor_set.WriteDescriptorImageInfo(1, image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindDescriptorSets(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1, |
| &descriptor_set.set_, 0, nullptr); |
| vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipe.Handle()); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08610"); |
| vk::CmdDraw(m_command_buffer.handle(), 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeSampler, ReductionModeFeature) { |
| TEST_DESCRIPTION("Test using VkSamplerReductionModeCreateInfo without required feature."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(Init()); |
| |
| VkSamplerReductionModeCreateInfo sampler_reduction_mode_ci = vku::InitStructHelper(); |
| sampler_reduction_mode_ci.reductionMode = VK_SAMPLER_REDUCTION_MODE_MIN; |
| |
| auto sampler_ci = SafeSaneSamplerCreateInfo(); |
| sampler_ci.pNext = &sampler_reduction_mode_ci; |
| CreateSamplerTest(*this, &sampler_ci, "VUID-VkSamplerCreateInfo-pNext-06726"); |
| } |
| |
| TEST_F(NegativeSampler, ReductionModeCubicIMG) { |
| TEST_DESCRIPTION("Create sampler with invalid combination of filter and reduction mode."); |
| AddRequiredExtensions(VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME); |
| AddRequiredExtensions(VK_IMG_FILTER_CUBIC_EXTENSION_NAME); |
| RETURN_IF_SKIP(Init()); |
| |
| VkSamplerReductionModeCreateInfo sampler_reduction_mode_ci = vku::InitStructHelper(); |
| sampler_reduction_mode_ci.reductionMode = VK_SAMPLER_REDUCTION_MODE_MAX; |
| VkSamplerCreateInfo sampler_ci = vku::InitStructHelper(&sampler_reduction_mode_ci); |
| sampler_ci.magFilter = VK_FILTER_CUBIC_EXT; |
| CreateSamplerTest(*this, &sampler_ci, "VUID-VkSamplerCreateInfo-magFilter-07911"); |
| } |
| |
| TEST_F(NegativeSampler, NonSeamlessCubeMapNotEnabled) { |
| TEST_DESCRIPTION("Validation should catch using NON_SEAMLESS_CUBE_MAP if the feature is not enabled."); |
| |
| AddRequiredExtensions(VK_EXT_NON_SEAMLESS_CUBE_MAP_EXTENSION_NAME); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| |
| RETURN_IF_SKIP(Init()); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.flags = VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-nonSeamlessCubeMap-06788"); |
| } |
| |
| TEST_F(NegativeSampler, BorderColorSwizzle) { |
| TEST_DESCRIPTION("Validate vkCreateSampler with VkSamplerBorderColorComponentMappingCreateInfoEXT"); |
| |
| AddRequiredExtensions(VK_EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME); |
| RETURN_IF_SKIP(Init()); |
| |
| VkSamplerBorderColorComponentMappingCreateInfoEXT border_color_component_mapping = |
| vku::InitStructHelper(); |
| border_color_component_mapping.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, |
| VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; |
| |
| VkSamplerCreateInfo sampler_create_info = SafeSaneSamplerCreateInfo(); |
| sampler_create_info.pNext = &border_color_component_mapping; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkSamplerBorderColorComponentMappingCreateInfoEXT-borderColorSwizzle-06437"); |
| vkt::Sampler sampler(*m_device, sampler_create_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeSampler, BorderColorValue) { |
| TEST_DESCRIPTION("Using a bad VkBorderColor value."); |
| RETURN_IF_SKIP(Init()); |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; |
| sampler_info.borderColor = static_cast<VkBorderColor>(0xFFFFBAD0); |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-addressModeU-01078"); |
| } |
| |
| TEST_F(NegativeSampler, CompareOpValue) { |
| TEST_DESCRIPTION("Using a bad VkCompareOp value."); |
| RETURN_IF_SKIP(Init()); |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.compareEnable = VK_TRUE; |
| sampler_info.compareOp = static_cast<VkCompareOp>(0xFFFFBAD0); |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-compareEnable-01080"); |
| } |
| |
| TEST_F(NegativeSampler, CustomBorderColorsFeature) { |
| TEST_DESCRIPTION("Don't turn on the customBorderColors feature"); |
| AddRequiredExtensions(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); |
| RETURN_IF_SKIP(Init()); |
| |
| VkSampler sampler = VK_NULL_HANDLE; |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT; |
| |
| VkSamplerCustomBorderColorCreateInfoEXT custom_color_cinfo = vku::InitStructHelper(); |
| custom_color_cinfo.format = VK_FORMAT_R32_SFLOAT; |
| sampler_info.pNext = &custom_color_cinfo; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkSamplerCreateInfo-customBorderColors-04085"); |
| vk::CreateSampler(device(), &sampler_info, NULL, &sampler); |
| m_errorMonitor->VerifyFound(); |
| } |