| /* |
| * Copyright (c) 2015-2023 The Khronos Group Inc. |
| * Copyright (c) 2015-2023 Valve Corporation |
| * Copyright (c) 2015-2023 LunarG, Inc. |
| * Copyright (c) 2015-2023 Google, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| */ |
| |
| #pragma once |
| |
| #include <vulkan/vulkan.h> |
| #include <vulkan/layer/vk_layer_settings_ext.h> |
| |
| #include "../layers/vk_lunarg_device_profile_api_layer.h" |
| |
| #if defined(VK_USE_PLATFORM_ANDROID_KHR) |
| #include <android/log.h> |
| #include <android_native_app_glue.h> |
| #endif |
| |
| #include <vulkan/utility/vk_format_utils.h> |
| #include <vulkan/utility/vk_struct_helper.hpp> |
| |
| #include "test_common.h" |
| #include "containers/custom_containers.h" |
| #include "generated/vk_extension_helper.h" |
| #include "render.h" |
| #include "utils/convert_utils.h" |
| #include "shader_templates.h" |
| |
| #include <algorithm> |
| #include <cmath> |
| #include <functional> |
| #include <limits> |
| #include <memory> |
| #include <string> |
| #include <unordered_set> |
| #include <vector> |
| #include <condition_variable> |
| |
| using std::string; |
| using std::vector; |
| |
| // MSVC and GCC define __SANITIZE_ADDRESS__ when compiling with address sanitization |
| // However, clang doesn't. Instead you have to use __has_feature to check. |
| #if defined(__clang__) |
| #if __has_feature(address_sanitizer) |
| #define VVL_ENABLE_ASAN 1 |
| #endif |
| #elif defined(__SANITIZE_ADDRESS__) |
| #define VVL_ENABLE_ASAN 1 |
| #endif |
| |
| #if defined(VVL_ENABLE_ASAN) |
| #if __has_include(<sanitizer/lsan_interface.h>) |
| #include <sanitizer/lsan_interface.h> |
| #else |
| #error The lsan_interface.h header was not found! |
| #endif |
| #endif |
| |
| #define OBJECT_LAYER_NAME "VK_LAYER_KHRONOS_validation" |
| |
| //-------------------------------------------------------------------------------------- |
| // Mesh and VertexFormat Data |
| //-------------------------------------------------------------------------------------- |
| |
| // Static arrays helper |
| template <class ElementT, size_t array_size> |
| size_t size(ElementT (&)[array_size]) { |
| return array_size; |
| } |
| |
| template <class ElementT, size_t array_size> |
| uint32_t size32(ElementT (&)[array_size]) { |
| return static_cast<uint32_t>(array_size); |
| } |
| |
| template <class Container> |
| uint32_t size32(const Container &c) { |
| return static_cast<uint32_t>(c.size()); |
| } |
| |
| // Format search helper |
| VkFormat FindSupportedDepthOnlyFormat(VkPhysicalDevice phy); |
| VkFormat FindSupportedStencilOnlyFormat(VkPhysicalDevice phy); |
| VkFormat FindSupportedDepthStencilFormat(VkPhysicalDevice phy); |
| |
| // Returns true if *any* requested features are available. |
| // Assumption is that the framework can successfully create an image as |
| // long as at least one of the feature bits is present (excepting VTX_BUF). |
| bool ImageFormatIsSupported(VkPhysicalDevice phy, VkFormat format, VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL, |
| VkFormatFeatureFlags features = ~VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT); |
| |
| // Returns true if format and *all* requested features are available. |
| bool ImageFormatAndFeaturesSupported(VkPhysicalDevice phy, VkFormat format, VkImageTiling tiling, VkFormatFeatureFlags features); |
| |
| // Returns true if format and *all* requested features are available. |
| bool ImageFormatAndFeaturesSupported(const VkInstance inst, const VkPhysicalDevice phy, const VkImageCreateInfo info, |
| const VkFormatFeatureFlags features); |
| |
| // Returns true if format and *all* requested features are available. |
| bool BufferFormatAndFeaturesSupported(VkPhysicalDevice phy, VkFormat format, VkFormatFeatureFlags features); |
| |
| // Simple sane SamplerCreateInfo boilerplate |
| VkSamplerCreateInfo SafeSaneSamplerCreateInfo(); |
| |
| // Dependent "false" type for the static assert, as GCC will evaluate |
| // non-dependent static_asserts even for non-instantiated templates |
| template <typename T> |
| struct AlwaysFalse : std::false_type {}; |
| |
| // Helpers to get nearest greater or smaller value (of float) -- useful for testing the boundary cases of Vulkan limits |
| template <typename T> |
| T NearestGreater(const T from) { |
| using Lim = std::numeric_limits<T>; |
| const auto positive_direction = Lim::has_infinity ? Lim::infinity() : Lim::max(); |
| |
| return std::nextafter(from, positive_direction); |
| } |
| |
| template <typename T> |
| T NearestSmaller(const T from) { |
| using Lim = std::numeric_limits<T>; |
| const auto negative_direction = Lim::has_infinity ? -Lim::infinity() : Lim::lowest(); |
| |
| return std::nextafter(from, negative_direction); |
| } |
| |
| // Defining VVL_TESTS_USE_CUSTOM_TEST_FRAMEWORK allows downstream users |
| // to inject custom test framework changes. This includes the ability |
| // to override the the base class of the VkLayerTest class so that |
| // appropriate test framework customizations can be injected into the |
| // class hierarchy at the closest possible place to the base class used |
| // by all validation layer tests. Downstream users can provide their |
| // own version of custom_test_framework.h to define the appropriate |
| // custom base class to use through the VkLayerTestBase type identifier. |
| #ifdef VVL_TESTS_USE_CUSTOM_TEST_FRAMEWORK |
| #include "framework/custom_test_framework.h" |
| #else |
| using VkLayerTestBase = VkRenderFramework; |
| #endif |
| |
| // VkLayerTest is the main GTest test class |
| // It is the root for all other test class variations |
| class VkLayerTest : public VkLayerTestBase { |
| public: |
| const char *kValidationLayerName = "VK_LAYER_KHRONOS_validation"; |
| const char *kSynchronization2LayerName = "VK_LAYER_KHRONOS_synchronization2"; |
| |
| void Init(VkPhysicalDeviceFeatures *features = nullptr, VkPhysicalDeviceFeatures2 *features2 = nullptr, |
| const VkCommandPoolCreateFlags flags = 0, void *instance_pnext = nullptr); |
| void AddSurfaceExtension(); |
| vkt::CommandBuffer *CommandBuffer(); |
| |
| template <typename Features> |
| VkPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2(Features &feature_query) { |
| VkPhysicalDeviceFeatures2 features2 = vku::InitStructHelper(&feature_query); |
| return GetPhysicalDeviceFeatures2(features2); |
| } |
| |
| template <typename Properties> |
| VkPhysicalDeviceProperties2 GetPhysicalDeviceProperties2(Properties &props_query) { |
| VkPhysicalDeviceProperties2 props2 = vku::InitStructHelper(&props_query); |
| return GetPhysicalDeviceProperties2(props2); |
| } |
| |
| template <typename Proc, bool assert_proc = true> |
| [[nodiscard]] const Proc GetInstanceProcAddr(const char *proc_name) const noexcept { |
| static_assert(std::is_pointer_v<Proc>); |
| |
| auto proc = reinterpret_cast<Proc>(vk::GetInstanceProcAddr(instance(), proc_name)); |
| if constexpr (assert_proc) { |
| assert(proc); |
| } |
| return proc; |
| } |
| |
| template <typename Proc, bool assert_proc = true> |
| [[nodiscard]] const Proc GetDeviceProcAddr(const char *proc_name) noexcept { |
| static_assert(std::is_pointer_v<Proc>); |
| |
| auto proc = reinterpret_cast<Proc>(vk::GetDeviceProcAddr(device(), proc_name)); |
| if constexpr (assert_proc) { |
| assert(proc); |
| } |
| return proc; |
| } |
| |
| bool IsDriver(VkDriverId driver_id); |
| |
| protected: |
| void SetTargetApiVersion(APIVersion target_api_version); |
| APIVersion DeviceValidationVersion() const; |
| bool LoadDeviceProfileLayer( |
| PFN_vkSetPhysicalDeviceFormatPropertiesEXT &fpvkSetPhysicalDeviceFormatPropertiesEXT, |
| PFN_vkGetOriginalPhysicalDeviceFormatPropertiesEXT &fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT); |
| bool LoadDeviceProfileLayer( |
| PFN_vkSetPhysicalDeviceFormatProperties2EXT &fpvkSetPhysicalDeviceFormatProperties2EXT, |
| PFN_vkGetOriginalPhysicalDeviceFormatProperties2EXT &fpvkGetOriginalPhysicalDeviceFormatProperties2EXT); |
| bool LoadDeviceProfileLayer(PFN_vkSetPhysicalDeviceLimitsEXT &fpvkSetPhysicalDeviceLimitsEXT, |
| PFN_vkGetOriginalPhysicalDeviceLimitsEXT &fpvkGetOriginalPhysicalDeviceLimitsEXT); |
| bool LoadDeviceProfileLayer(PFN_vkSetPhysicalDeviceFeaturesEXT &fpvkSetPhysicalDeviceFeaturesEXT, |
| PFN_vkGetOriginalPhysicalDeviceFeaturesEXT &fpvkGetOriginalPhysicalDeviceFeaturesEXT); |
| bool LoadDeviceProfileLayer(PFN_VkSetPhysicalDeviceProperties2EXT &fpvkSetPhysicalDeviceProperties2EXT); |
| |
| VkLayerTest(); |
| }; |
| |
| template <> |
| VkPhysicalDeviceFeatures2 VkLayerTest::GetPhysicalDeviceFeatures2(VkPhysicalDeviceFeatures2 &feature_query); |
| |
| template <> |
| VkPhysicalDeviceProperties2 VkLayerTest::GetPhysicalDeviceProperties2(VkPhysicalDeviceProperties2 &props2); |
| |
| // TODO - Want to remove - don't add to any new tests |
| class VkPositiveLayerTest : public VkLayerTest { |
| public: |
| protected: |
| }; |
| |
| class VkBestPracticesLayerTest : public VkLayerTest { |
| public: |
| void InitBestPracticesFramework(); |
| void InitBestPracticesFramework(const char* ValidationChecksToEnable); |
| |
| protected: |
| VkValidationFeatureEnableEXT enables_[1] = {VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT}; |
| VkValidationFeatureDisableEXT disables_[4] = { |
| VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT, VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT, |
| VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT, VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT}; |
| VkValidationFeaturesEXT features_ = {VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, nullptr, 1, enables_, 4, disables_}; |
| }; |
| |
| class VkAmdBestPracticesLayerTest : public VkBestPracticesLayerTest {}; |
| class VkArmBestPracticesLayerTest : public VkBestPracticesLayerTest { |
| public: |
| std::unique_ptr<VkImageObj> CreateImage(VkFormat format, const uint32_t width, const uint32_t height, |
| VkImageUsageFlags attachment_usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| VkRenderPass CreateRenderPass(VkFormat format, VkAttachmentLoadOp load_op = VK_ATTACHMENT_LOAD_OP_CLEAR, |
| VkAttachmentStoreOp store_op = VK_ATTACHMENT_STORE_OP_STORE); |
| VkFramebuffer CreateFramebuffer(const uint32_t width, const uint32_t height, VkImageView image_view, VkRenderPass renderpass); |
| VkSampler CreateDefaultSampler(); |
| }; |
| class VkNvidiaBestPracticesLayerTest : public VkBestPracticesLayerTest {}; |
| |
| class VkGpuAssistedLayerTest : public virtual VkLayerTest { |
| public: |
| void InitGpuAvFramework(); |
| |
| VkValidationFeaturesEXT GetValidationFeatures(); |
| void ShaderBufferSizeTest(VkDeviceSize buffer_size, VkDeviceSize binding_offset, VkDeviceSize binding_range, |
| VkDescriptorType descriptor_type, const char *fragment_shader, const char *expected_error, bool shader_objects = false); |
| |
| protected: |
| bool CanEnableGpuAV(); |
| }; |
| |
| class NegativeDebugPrintf : public VkLayerTest { |
| public: |
| void InitDebugPrintfFramework(); |
| |
| protected: |
| }; |
| |
| class VkSyncValTest : public VkLayerTest { |
| public: |
| void InitSyncValFramework(bool enable_queue_submit_validation = false); |
| |
| protected: |
| VkValidationFeatureEnableEXT enables_[1] = {VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT}; |
| VkValidationFeatureDisableEXT disables_[4] = { |
| VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT, VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT, |
| VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT, VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT}; |
| VkValidationFeaturesEXT features_ = {VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, nullptr, 1, enables_, 4, disables_}; |
| }; |
| |
| class AndroidHardwareBufferTest : public VkLayerTest {}; |
| class NegativeAndroidHardwareBuffer : public AndroidHardwareBufferTest {}; |
| class PositiveAndroidHardwareBuffer : public AndroidHardwareBufferTest {}; |
| |
| class AtomicTest : public VkLayerTest {}; |
| class NegativeAtomic : public AtomicTest {}; |
| class PositiveAtomic : public AtomicTest {}; |
| |
| class BufferTest : public VkLayerTest {}; |
| class NegativeBuffer : public BufferTest {}; |
| class PositiveBuffer : public BufferTest {}; |
| |
| class CommandTest : public VkLayerTest {}; |
| class NegativeCommand : public CommandTest {}; |
| class PositiveCommand : public CommandTest {}; |
| |
| class DescriptorsTest : public VkLayerTest {}; |
| class NegativeDescriptors : public DescriptorsTest {}; |
| class PositiveDescriptors : public DescriptorsTest {}; |
| |
| class PushDescriptorTest : public VkLayerTest {}; |
| class NegativePushDescriptor : public PushDescriptorTest {}; |
| class PositivePushDescriptor : public PushDescriptorTest {}; |
| |
| class DescriptorBufferTest : public VkLayerTest { |
| public: |
| void InitBasicDescriptorBuffer(void *pNextFeatures = nullptr); |
| }; |
| class NegativeDescriptorBuffer : public DescriptorBufferTest {}; |
| class PositiveDescriptorBuffer : public DescriptorBufferTest {}; |
| |
| class DescriptorIndexingTest : public VkLayerTest { |
| public: |
| void InitBasicDescriptorIndexing(void *pNextFeatures = nullptr); |
| VkPhysicalDeviceDescriptorIndexingFeatures descriptor_indexing_features; |
| void ComputePipelineShaderTest(const char *shader, std::vector<VkDescriptorSetLayoutBinding> &bindings); |
| }; |
| class NegativeDescriptorIndexing : public DescriptorIndexingTest {}; |
| class PositiveDescriptorIndexing : public DescriptorIndexingTest {}; |
| |
| class NegativeDeviceQueue : public VkLayerTest {}; |
| |
| class DynamicRenderingTest : public VkLayerTest { |
| public: |
| void InitBasicDynamicRendering(void *pNextFeatures = nullptr); |
| }; |
| class NegativeDynamicRendering : public DynamicRenderingTest {}; |
| class PositiveDynamicRendering : public DynamicRenderingTest {}; |
| |
| class DynamicStateTest : public VkLayerTest { |
| public: |
| void InitBasicExtendedDynamicState(); // enables VK_EXT_extended_dynamic_state |
| void InitBasicExtendedDynamicState3(VkPhysicalDeviceExtendedDynamicState3FeaturesEXT &features); |
| }; |
| class NegativeDynamicState : public DynamicStateTest { |
| // helper functions for tests in this file |
| public: |
| // VK_EXT_extended_dynamic_state - not calling vkCmdSet before draw |
| void ExtendedDynamicStateDrawNotSet(VkDynamicState dynamic_state, const char *vuid); |
| // VK_EXT_extended_dynamic_state3 - Create a pipeline with dynamic state, but the feature disabled |
| void ExtendedDynamicState3PipelineFeatureDisabled(VkDynamicState dynamic_state, const char *vuid); |
| // VK_EXT_line_rasterization - Init with LineRasterization features off |
| void InitLineRasterizationFeatureDisabled(); |
| }; |
| class PositiveDynamicState : public DynamicStateTest {}; |
| |
| class ExternalMemorySyncTest : public VkLayerTest { |
| protected: |
| #ifdef VK_USE_PLATFORM_WIN32_KHR |
| using ExternalHandle = HANDLE; |
| #else |
| using ExternalHandle = int; |
| #endif |
| }; |
| class NegativeExternalMemorySync : public ExternalMemorySyncTest {}; |
| class PositiveExternalMemorySync : public ExternalMemorySyncTest {}; |
| |
| class FragmentShadingRateTest : public VkLayerTest {}; |
| class NegativeFragmentShadingRate : public FragmentShadingRateTest {}; |
| class PositiveFragmentShadingRate : public FragmentShadingRateTest {}; |
| |
| class NegativeGeometryTessellation : public VkLayerTest {}; |
| class PositiveGeometryTessellation : public VkLayerTest {}; |
| |
| class GraphicsLibraryTest : public VkLayerTest { |
| public: |
| void InitBasicGraphicsLibrary(void *pNextFeatures = nullptr); |
| }; |
| class NegativeGraphicsLibrary : public GraphicsLibraryTest {}; |
| class PositiveGraphicsLibrary : public GraphicsLibraryTest {}; |
| |
| class HostImageCopyTest : public VkLayerTest { |
| public: |
| void InitHostImageCopyTest(const VkImageCreateInfo &image_ci); |
| bool CopyLayoutSupported(const std::vector<VkImageLayout> ©_src_layouts, const std::vector<VkImageLayout> ©_dst_layouts, |
| VkImageLayout layout); |
| VkFormat compressed_format = VK_FORMAT_UNDEFINED; |
| bool separate_depth_stencil = false; |
| std::vector<VkImageLayout> copy_src_layouts; |
| std::vector<VkImageLayout> copy_dst_layouts; |
| }; |
| class NegativeHostImageCopy : public HostImageCopyTest {}; |
| class PositiveHostImageCopy : public HostImageCopyTest {}; |
| |
| class ImageTest : public VkLayerTest { |
| public: |
| VkImageCreateInfo DefaultImageInfo(); |
| }; |
| class NegativeImage : public ImageTest {}; |
| class PositiveImage : public ImageTest {}; |
| |
| class ImageDrmTest : public VkLayerTest { |
| public: |
| void InitBasicImageDrm(void *pNextFeatures = nullptr); |
| std::vector<uint64_t> GetFormatModifier(VkFormat format, VkFormatFeatureFlags2 features, uint32_t plane_count = 1); |
| }; |
| class NegativeImageDrm : public ImageDrmTest {}; |
| class PositiveImageDrm : public ImageDrmTest {}; |
| |
| class ImagelessFramebufferTest : public VkLayerTest {}; |
| class NegativeImagelessFramebuffer : public ImagelessFramebufferTest {}; |
| class PositiveImagelessFramebuffer : public ImagelessFramebufferTest {}; |
| |
| class NegativeInstanceless : public VkLayerTest {}; |
| |
| class PositiveInstance : public VkLayerTest {}; |
| |
| class MemoryTest : public VkLayerTest {}; |
| class NegativeMemory : public MemoryTest {}; |
| class PositiveMemory : public MemoryTest {}; |
| |
| class MeshTest : public VkLayerTest {}; |
| class NegativeMesh : public MeshTest {}; |
| class PositiveMesh : public MeshTest {}; |
| |
| class NegativeMultiview : public VkLayerTest {}; |
| |
| class NegativeObjectLifetime : public VkLayerTest {}; |
| |
| class NegativePipelineAdvancedBlend : public VkLayerTest {}; |
| |
| class PipelineLayoutTest : public VkLayerTest {}; |
| class NegativePipelineLayout : public PipelineLayoutTest {}; |
| class PositivePipelineLayout : public PipelineLayoutTest {}; |
| |
| class PipelineTopologyTest : public VkLayerTest {}; |
| class NegativePipelineTopology : public PipelineTopologyTest {}; |
| class PositivePipelineTopology : public PipelineTopologyTest {}; |
| |
| class PipelineTest : public VkLayerTest {}; |
| class NegativePipeline : public PipelineTest {}; |
| class PositivePipeline : public PipelineTest {}; |
| |
| class NegativePortabilitySubset : public VkLayerTest {}; |
| |
| class ProtectedMemoryTest : public VkLayerTest {}; |
| class NegativeProtectedMemory : public ProtectedMemoryTest {}; |
| class PositiveProtectedMemory : public ProtectedMemoryTest {}; |
| |
| class QueryTest : public VkLayerTest { |
| public: |
| bool HasZeroTimestampValidBits(); |
| }; |
| class NegativeQuery : public QueryTest {}; |
| class PositiveQuery : public QueryTest {}; |
| |
| class RayTracingTest : public virtual VkLayerTest { |
| public: |
| void InitFrameworkForRayTracingTest(VkRenderFramework *framework, bool is_khr, |
| VkPhysicalDeviceFeatures2KHR *features2 = nullptr, |
| VkValidationFeaturesEXT *enabled_features = nullptr); |
| |
| void OOBRayTracingShadersTestBody(bool gpu_assisted); |
| }; |
| class NegativeRayTracing : public RayTracingTest {}; |
| class PositiveRayTracing : public RayTracingTest {}; |
| class NegativeRayTracingNV : public NegativeRayTracing {}; |
| class PositiveRayTracingNV : public PositiveRayTracing {}; |
| |
| class RayTracingPipelineTest : public RayTracingTest {}; |
| class NegativeRayTracingPipeline : public RayTracingPipelineTest {}; |
| class PositiveRayTracingPipeline : public RayTracingPipelineTest {}; |
| class NegativeRayTracingPipelineNV : public NegativeRayTracingPipeline {}; |
| class PositiveRayTracingPipelineNV : public PositiveRayTracingPipeline {}; |
| |
| class GpuAssistedRayTracingTest : public VkGpuAssistedLayerTest, public RayTracingTest {}; |
| class NegativeGpuAssistedRayTracing : public GpuAssistedRayTracingTest {}; |
| class NegativeGpuAssistedRayTracingNV : public NegativeGpuAssistedRayTracing {}; |
| |
| class RenderPassTest : public VkLayerTest {}; |
| class NegativeRenderPass : public RenderPassTest {}; |
| class PositiveRenderPass : public RenderPassTest {}; |
| |
| class RobustnessTest : public VkLayerTest {}; |
| class NegativeRobustness : public RobustnessTest {}; |
| class PositiveRobustness : public RobustnessTest {}; |
| |
| class SamplerTest : public VkLayerTest {}; |
| class NegativeSampler : public SamplerTest {}; |
| class PositiveSampler : public SamplerTest {}; |
| |
| class ShaderComputeTest : public VkLayerTest {}; |
| class NegativeShaderCompute : public ShaderComputeTest {}; |
| class PositiveShaderCompute : public ShaderComputeTest {}; |
| |
| class ShaderObjectTest : public VkLayerTest { |
| vkt::Buffer vertexBuffer; |
| |
| public: |
| void InitBasicShaderObject(void *pNextFeatures = nullptr, APIVersion targetApiVersion = VK_API_VERSION_1_1, bool coreFeatures = true); |
| void BindVertFragShader(const vkt::Shader &vertShader, const vkt::Shader &fragShader); |
| void BindCompShader(const vkt::Shader &compShader); |
| void SetDefaultDynamicStates(const std::vector<VkDynamicState>& exclude = {}, bool tessellation = false, VkCommandBuffer commandBuffer = VK_NULL_HANDLE); |
| }; |
| class NegativeShaderObject : public ShaderObjectTest {}; |
| class PositiveShaderObject : public ShaderObjectTest {}; |
| |
| class ShaderInterfaceTest : public VkLayerTest {}; |
| class NegativeShaderInterface : public ShaderInterfaceTest {}; |
| class PositiveShaderInterface : public ShaderInterfaceTest {}; |
| |
| class PositiveShaderImageAccess : public VkLayerTest {}; |
| |
| class ShaderLimitsTest : public VkLayerTest {}; |
| class NegativeShaderLimits : public ShaderLimitsTest {}; |
| class PositiveShaderLimits : public ShaderLimitsTest {}; |
| |
| class NegativeShaderMesh : public VkLayerTest {}; |
| |
| class ShaderPushConstantsTest : public VkLayerTest {}; |
| class NegativeShaderPushConstants : public ShaderPushConstantsTest {}; |
| class PositiveShaderPushConstants : public ShaderPushConstantsTest {}; |
| |
| class ShaderSpirvTest : public VkLayerTest {}; |
| class NegativeShaderSpirv : public ShaderSpirvTest {}; |
| class PositiveShaderSpirv : public ShaderSpirvTest {}; |
| |
| class ShaderStorageImageTest : public VkLayerTest {}; |
| class NegativeShaderStorageImage : public ShaderStorageImageTest {}; |
| class PositiveShaderStorageImage : public ShaderStorageImageTest {}; |
| |
| class ShaderStorageTexelTest : public VkLayerTest {}; |
| class NegativeShaderStorageTexel : public ShaderStorageTexelTest {}; |
| class PositiveShaderStorageTexel : public ShaderStorageTexelTest {}; |
| |
| class SparseTest : public VkLayerTest {}; |
| class NegativeSparseImage : public SparseTest {}; |
| class PositiveSparseImage : public SparseTest {}; |
| class NegativeSparseBuffer : public SparseTest {}; |
| class PositiveSparseBuffer : public SparseTest {}; |
| |
| class NegativeSubgroup : public VkLayerTest {}; |
| |
| class SubpassTest : public VkLayerTest {}; |
| class NegativeSubpass : public SubpassTest {}; |
| class PositiveSubpass : public SubpassTest {}; |
| |
| class SyncObjectTest : public VkLayerTest { |
| protected: |
| #ifdef VK_USE_PLATFORM_WIN32_KHR |
| using ExternalHandle = HANDLE; |
| #else |
| using ExternalHandle = int; |
| #endif |
| }; |
| class NegativeSyncObject : public SyncObjectTest {}; |
| class PositiveSyncObject : public SyncObjectTest {}; |
| |
| class NegativeTransformFeedback : public VkLayerTest { |
| public: |
| void InitBasicTransformFeedback(void *pNextFeatures = nullptr); |
| }; |
| |
| class PositiveTooling : public VkLayerTest {}; |
| |
| class VertexInputTest : public VkLayerTest {}; |
| class NegativeVertexInput : public VertexInputTest {}; |
| class PositiveVertexInput : public VertexInputTest {}; |
| |
| class NegativeViewportInheritance : public VkLayerTest {}; |
| |
| class WsiTest : public VkLayerTest {}; |
| class NegativeWsi : public WsiTest {}; |
| class PositiveWsi : public WsiTest {}; |
| |
| class YcbcrTest : public VkLayerTest { |
| public: |
| void InitBasicYcbcr(void *pNextFeatures = nullptr); |
| }; |
| class NegativeYcbcr : public YcbcrTest {}; |
| class PositiveYcbcr : public YcbcrTest {}; |
| |
| class CooperativeMatrixTest : public VkLayerTest {}; |
| class NegativeShaderCooperativeMatrix : public CooperativeMatrixTest {}; |
| class PositiveShaderCooperativeMatrix : public CooperativeMatrixTest {}; |
| |
| class ParentTest : public VkLayerTest { |
| public: |
| ~ParentTest(); |
| vkt::Device *m_second_device = nullptr; |
| }; |
| class NegativeParent : public ParentTest {}; |
| |
| // Thread safety tests and other tests that implement non-trivial threading scenarios |
| class ThreadingTest : public VkLayerTest {}; |
| class NegativeThreading : public ThreadingTest {}; |
| class PositiveThreading : public ThreadingTest {}; |
| |
| struct OneOffDescriptorSet { |
| vkt::Device *device_; |
| VkDescriptorPool pool_; |
| vkt::DescriptorSetLayout layout_; |
| VkDescriptorSet set_; |
| typedef std::vector<VkDescriptorSetLayoutBinding> Bindings; |
| |
| // Only one member of ResourceInfo object contains a value. |
| // The pointers to Image/Buffer/BufferView info structures can't be stored in 'descriptor_writes' |
| // during WriteDescriptor call, because subsequent calls can reallocate which invalidates stored pointers. |
| // When UpdateDescriptorSets is called it's safe to initialize the pointers. |
| struct ResourceInfo { |
| std::optional<VkDescriptorImageInfo> image_info; |
| std::optional<VkDescriptorBufferInfo> buffer_info; |
| std::optional<VkBufferView> buffer_view; |
| }; |
| std::vector<ResourceInfo> resource_infos; |
| std::vector<VkWriteDescriptorSet> descriptor_writes; |
| |
| OneOffDescriptorSet(vkt::Device *device, const Bindings &bindings, VkDescriptorSetLayoutCreateFlags layout_flags = 0, |
| void *layout_pnext = NULL, VkDescriptorPoolCreateFlags poolFlags = 0, void *allocate_pnext = NULL); |
| ~OneOffDescriptorSet(); |
| bool Initialized(); |
| void Clear(); |
| void WriteDescriptorBufferInfo(int binding, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range, |
| VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uint32_t arrayElement = 0); |
| void WriteDescriptorBufferView(int binding, VkBufferView buffer_view, |
| VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, |
| uint32_t arrayElement = 0); |
| void WriteDescriptorImageInfo(int binding, VkImageView image_view, VkSampler sampler, |
| VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, uint32_t arrayElement = 0); |
| void UpdateDescriptorSets(); |
| |
| private: |
| void AddDescriptorWrite(uint32_t binding, uint32_t array_element, VkDescriptorType descriptor_type); |
| }; |
| |
| template <typename T> |
| bool IsValidVkStruct(const T &s) { |
| return vku::GetSType<T>() == s.sType; |
| } |
| |
| class BarrierQueueFamilyBase { |
| public: |
| struct QueueFamilyObjs { |
| uint32_t index; |
| // We would use std::unique_ptr, but this triggers a compiler error on older compilers |
| vkt::Queue *queue = nullptr; |
| vkt::CommandPool *command_pool = nullptr; |
| vkt::CommandBuffer *command_buffer = nullptr; |
| vkt::CommandBuffer *command_buffer2 = nullptr; |
| ~QueueFamilyObjs(); |
| void Init(vkt::Device *device, uint32_t qf_index, VkQueue qf_queue, VkCommandPoolCreateFlags cp_flags); |
| }; |
| |
| struct Context { |
| VkLayerTest *layer_test; |
| uint32_t default_index; |
| std::unordered_map<uint32_t, QueueFamilyObjs> queue_families; |
| Context(VkLayerTest *test, const std::vector<uint32_t> &queue_family_indices); |
| void Reset(); |
| }; |
| |
| BarrierQueueFamilyBase(Context *context) : context_(context), image_(context->layer_test->DeviceObj()) {} |
| |
| QueueFamilyObjs *GetQueueFamilyInfo(Context *context, uint32_t qfi); |
| |
| enum Modifier { |
| NONE, |
| DOUBLE_RECORD, |
| DOUBLE_COMMAND_BUFFER, |
| }; |
| |
| static const uint32_t kInvalidQueueFamily = vvl::kU32Max; |
| Context *context_; |
| VkImageObj image_; |
| vkt::Buffer buffer_; |
| }; |
| |
| class BarrierQueueFamilyTestHelper : public BarrierQueueFamilyBase { |
| public: |
| BarrierQueueFamilyTestHelper(Context *context) : BarrierQueueFamilyBase(context) {} |
| // Init with queue families non-null for CONCURRENT sharing mode (which requires them) |
| void Init(std::vector<uint32_t> *families, bool image_memory = true, bool buffer_memory = true); |
| |
| void operator()(const std::string &img_err, const std::string &buf_err = "", uint32_t src = VK_QUEUE_FAMILY_IGNORED, |
| uint32_t dst = VK_QUEUE_FAMILY_IGNORED, uint32_t queue_family_index = kInvalidQueueFamily, |
| Modifier mod = Modifier::NONE); |
| |
| void operator()(uint32_t src = VK_QUEUE_FAMILY_IGNORED, uint32_t dst = VK_QUEUE_FAMILY_IGNORED, |
| uint32_t queue_family_index = kInvalidQueueFamily, Modifier mod = Modifier::NONE) { |
| (*this)("", "", src, dst, queue_family_index, mod); |
| } |
| |
| VkImageMemoryBarrier image_barrier_; |
| VkBufferMemoryBarrier buffer_barrier_; |
| }; |
| |
| // TODO - Only works with extensions enabled, not using Vulkan1.3 (uses KHR functions) |
| class Barrier2QueueFamilyTestHelper : public BarrierQueueFamilyBase { |
| public: |
| Barrier2QueueFamilyTestHelper(Context *context) : BarrierQueueFamilyBase(context) {} |
| // Init with queue families non-null for CONCURRENT sharing mode (which requires them) |
| void Init(std::vector<uint32_t> *families, bool image_memory = true, bool buffer_memory = true); |
| |
| void operator()(const std::string &img_err, const std::string &buf_err = "", uint32_t src = VK_QUEUE_FAMILY_IGNORED, |
| uint32_t dst = VK_QUEUE_FAMILY_IGNORED, uint32_t queue_family_index = kInvalidQueueFamily, |
| Modifier mod = Modifier::NONE); |
| |
| void operator()(uint32_t src = VK_QUEUE_FAMILY_IGNORED, uint32_t dst = VK_QUEUE_FAMILY_IGNORED, |
| uint32_t queue_family_index = kInvalidQueueFamily, Modifier mod = Modifier::NONE) { |
| (*this)("", "", src, dst, queue_family_index, mod); |
| } |
| |
| VkImageMemoryBarrier2KHR image_barrier_; |
| VkBufferMemoryBarrier2KHR buffer_barrier_; |
| }; |
| |
| struct DebugUtilsLabelCheckData { |
| std::function<void(const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, DebugUtilsLabelCheckData *)> callback; |
| size_t count; |
| }; |
| |
| bool operator==(const VkDebugUtilsLabelEXT &rhs, const VkDebugUtilsLabelEXT &lhs); |
| |
| VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, |
| VkDebugUtilsMessageTypeFlagsEXT messageTypes, |
| const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData); |
| |
| #if GTEST_IS_THREADSAFE |
| struct ThreadTestData { |
| VkCommandBuffer commandBuffer; |
| VkDevice device; |
| VkEvent event; |
| VkDescriptorSet descriptorSet; |
| VkBuffer buffer; |
| uint32_t binding; |
| std::atomic<bool> *bailout; |
| }; |
| |
| void AddToCommandBuffer(ThreadTestData *); |
| void UpdateDescriptor(ThreadTestData *); |
| #endif // GTEST_IS_THREADSAFE |
| |
| // Helper class that fails the tests with a stuck worker thread. |
| // Its purpose is similar to an assert. We assume the code is correct. |
| // Then, in case of a bug or regression, the CI will continue to operate. |
| // Usage Example: |
| // TEST_F(VkLayerTest, MyTrickyTestWithThreads) { |
| // // The constructor parameter is the number of the worker threads |
| // ThreadTimeoutHelper timeout_helper(2); |
| // auto worker = [&]() { |
| // auto timeout_guard = timeout_helper.ThreadGuard(); |
| // // Some code here |
| // }; |
| // std::thread t0(worker); |
| // std::thread t1(worker); |
| // if (!timeout_helper.WaitForThreads(60)) ADD_FAILURE() << "It's time to move on"; |
| // t0.join(); |
| // t1.join(); |
| // } |
| class ThreadTimeoutHelper { |
| public: |
| explicit ThreadTimeoutHelper(int thread_count = 1) : active_threads_(thread_count) {} |
| bool WaitForThreads(int timeout_in_seconds); |
| |
| struct Guard { |
| Guard(ThreadTimeoutHelper &timeout_helper) : timeout_helper_(timeout_helper) {} |
| Guard(const Guard &) = delete; |
| Guard &operator=(const Guard &) = delete; |
| |
| ~Guard() { timeout_helper_.OnThreadDone(); } |
| |
| ThreadTimeoutHelper &timeout_helper_; |
| }; |
| // Mandatory elision of copy/move operations guarantees the destructor is not called |
| // (even in the presence of copy/move constructor) and the object is constructed directly |
| // into the destination storage: https://en.cppreference.com/w/cpp/language/copy_elision |
| Guard ThreadGuard() { return Guard(*this); } |
| |
| private: |
| void OnThreadDone(); |
| |
| std::mutex active_thread_mutex_; |
| int active_threads_; |
| |
| std::condition_variable cv_; |
| std::mutex mutex_; |
| }; |
| |
| void ReleaseNullFence(ThreadTestData *); |
| |
| void TestRenderPassCreate(ErrorMonitor *error_monitor, const vkt::Device &device, const VkRenderPassCreateInfo &create_info, |
| bool rp2_supported, const char *rp1_vuid, const char *rp2_vuid); |
| void PositiveTestRenderPassCreate(ErrorMonitor *error_monitor, const vkt::Device &device, const VkRenderPassCreateInfo &create_info, |
| bool rp2_supported); |
| void PositiveTestRenderPass2KHRCreate(const vkt::Device &device, const VkRenderPassCreateInfo2KHR &create_info); |
| void TestRenderPass2KHRCreate(ErrorMonitor &error_monitor, const vkt::Device &device, const VkRenderPassCreateInfo2KHR &create_info, |
| const std::initializer_list<const char *> &vuids); |
| void TestRenderPassBegin(ErrorMonitor *error_monitor, const VkDevice device, const VkCommandBuffer command_buffer, |
| const VkRenderPassBeginInfo *begin_info, bool rp2Supported, const char *rp1_vuid, const char *rp2_vuid); |
| |
| // Helpers for the tests below |
| void ValidOwnershipTransferOp(ErrorMonitor *monitor, vkt::CommandBuffer *cb, VkPipelineStageFlags src_stages, |
| VkPipelineStageFlags dst_stages, const VkBufferMemoryBarrier *buf_barrier, |
| const VkImageMemoryBarrier *img_barrier); |
| |
| void ValidOwnershipTransferOp(ErrorMonitor *monitor, vkt::CommandBuffer *cb, const VkBufferMemoryBarrier2KHR *buf_barrier, |
| const VkImageMemoryBarrier2KHR *img_barrier); |
| |
| void ValidOwnershipTransfer(ErrorMonitor *monitor, vkt::CommandBuffer *cb_from, vkt::CommandBuffer *cb_to, |
| VkPipelineStageFlags src_stages, VkPipelineStageFlags dst_stages, |
| const VkBufferMemoryBarrier *buf_barrier, const VkImageMemoryBarrier *img_barrier); |
| |
| void ValidOwnershipTransfer(ErrorMonitor *monitor, vkt::CommandBuffer *cb_from, vkt::CommandBuffer *cb_to, |
| const VkBufferMemoryBarrier2KHR *buf_barrier, const VkImageMemoryBarrier2KHR *img_barrier); |
| |
| VkResult GPDIFPHelper(VkPhysicalDevice dev, const VkImageCreateInfo *ci, VkImageFormatProperties *limits = nullptr); |
| |
| VkFormat FindFormatWithoutFeatures(VkPhysicalDevice gpu, VkImageTiling tiling, |
| VkFormatFeatureFlags undesired_features = vvl::kU32Max); |
| |
| VkFormat FindFormatWithoutFeatures2(VkPhysicalDevice gpu, VkImageTiling tiling, VkFormatFeatureFlags2 undesired_features); |
| |
| bool SemaphoreExportImportSupported(VkPhysicalDevice gpu, VkExternalSemaphoreHandleTypeFlagBits handle_type); |
| |
| void SetImageLayout(vkt::Device *device, VkImageAspectFlags aspect, VkImage image, VkImageLayout image_layout); |
| |
| void AllocateDisjointMemory(vkt::Device *device, PFN_vkGetImageMemoryRequirements2KHR fp, VkImage mp_image, |
| VkDeviceMemory *mp_image_mem, VkImageAspectFlagBits plane); |
| |
| void CreateSamplerTest(VkLayerTest &test, const VkSamplerCreateInfo *pCreateInfo, const std::string &code = ""); |
| |
| void CreateBufferTest(VkLayerTest &test, const VkBufferCreateInfo *pCreateInfo, const std::string &code = ""); |
| |
| void CreateImageTest(VkLayerTest &test, const VkImageCreateInfo *pCreateInfo, const std::string &code = ""); |
| |
| void CreateBufferViewTest(VkLayerTest &test, const VkBufferViewCreateInfo *pCreateInfo, const std::vector<std::string> &codes); |
| |
| void CreateImageViewTest(VkLayerTest &test, const VkImageViewCreateInfo *pCreateInfo, const std::string &code = ""); |
| |
| void print_android(const char *c); |