blob: 04601b56996fb22cccac64531cbe48ac6ba9c8b7 [file] [log] [blame]
/*
* Copyright (c) 2015-2025 The Khronos Group Inc.
* Copyright (c) 2015-2025 Valve Corporation
* Copyright (c) 2015-2025 LunarG, Inc.
* Copyright (c) 2015-2025 Google, Inc.
* Copyright (C) 2025 Arm Limited.
*
* 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 "../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>
// Remove Windows macro that prevents usage of its name in any scope of the program.
// For example, BitstreamBuffer::MemoryBarrier() won't compile on ARM64.
#if defined(VK_USE_PLATFORM_WIN32_KHR) && defined(MemoryBarrier)
#undef MemoryBarrier
#endif
#include "binding.h"
#include "containers/limits.h"
#include "render.h"
#include <vector>
#include <array> // Required for Windows in many tests
// 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
// GCC defines __SANITIZE_THREAD__ when compiling with address sanitization
// However, clang doesn't. Instead you have to use __has_feature to check.
#if defined(__clang__)
#if __has_feature(thread_sanitizer)
#define VVL_ENABLE_TSAN 1
#endif
#elif defined(__SANITIZE_THREAD__)
#define VVL_ENABLE_TSAN 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"
[[maybe_unused]] static const VkBool32 kVkFalse = VK_FALSE;
[[maybe_unused]] static const VkBool32 kVkTrue = VK_TRUE;
// This is only for tests where you have a good reason to have more than the default (10) duplicate message limit.
// It is highly suggested you first try to breakup your test up into smaller tests if you are trying to use this.
static const VkLayerSettingEXT kDisableMessageLimitSetting = {OBJECT_LAYER_NAME, "enable_message_limit",
VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkFalse};
[[maybe_unused]] static VkLayerSettingsCreateInfoEXT kDisableMessageLimit = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT,
nullptr, 1, &kDisableMessageLimitSetting};
// Static arrays helper
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 gpu);
VkFormat FindSupportedStencilOnlyFormat(VkPhysicalDevice gpu);
VkFormat FindSupportedDepthStencilFormat(VkPhysicalDevice gpu);
// 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 FormatIsSupported(VkPhysicalDevice gpu, 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 FormatFeaturesAreSupported(VkPhysicalDevice gpu, VkFormat format, VkImageTiling tiling, VkFormatFeatureFlags features);
bool FormatFeatures2AreSupported(VkPhysicalDevice gpu, VkFormat format, VkImageTiling tiling, VkFormatFeatureFlags2 features);
// Small wrapprer around vkGetPhysicalDeviceImageFormatProperties
VkResult GetImageFormatProps(VkPhysicalDevice gpu, const VkImageCreateInfo &ci, VkImageFormatProperties &out_limits);
// Returns true if format and *all* requested features are available.
bool IsImageFormatSupported(VkPhysicalDevice gpu, const VkImageCreateInfo &ci, const VkFormatFeatureFlags features);
// Returns true if format and *all* requested features are available.
bool BufferFormatAndFeaturesSupported(VkPhysicalDevice gpu, VkFormat format, VkFormatFeatureFlags features);
// Simple sane SamplerCreateInfo boilerplate
VkSamplerCreateInfo SafeSaneSamplerCreateInfo(void *p_next = nullptr);
// 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
float NearestGreater(const float from);
float NearestSmaller(const float from);
// 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,
void *instance_pnext = nullptr);
void AddSurfaceExtension();
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;
}
APIVersion DeviceValidationVersion() const;
// Helpers to quickly create a Handle and check it gives a certain VU error
void CreateSamplerTest(const VkSamplerCreateInfo &create_info, const char *vuid);
void CreateBufferTest(const VkBufferCreateInfo &create_info, const char *vuid);
void CreateImageTest(const VkImageCreateInfo &create_info, const char *vuid);
void CreateBufferViewTest(const VkBufferViewCreateInfo &create_info, const char *vuid);
void CreateImageViewTest(const VkImageViewCreateInfo &create_info, const char *vuid);
void CreateRenderPassTest(const VkRenderPassCreateInfo &create_info, bool rp2_supported, const char *rp1_vuid,
const char *rp2_vuid);
void CreateRenderPassBeginTest(const VkCommandBuffer command_buffer, const VkRenderPassBeginInfo *begin_info,
bool rp2_supported, const char *rp1_vuid, const char *rp2_vuid);
VkResolveModeFlagBits FindSupportedDepthResolveMode();
VkResolveModeFlagBits FindSupportedStencilResolveMode();
protected:
void SetTargetApiVersion(APIVersion target_api_version);
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);
class VkBestPracticesLayerTest : public VkLayerTest {
public:
void InitBestPracticesFramework(const char* vendor_checks_to_enable = nullptr);
void InitBestPractices(const char* vendor_checks_to_enable = nullptr);
protected:
VkValidationFeatureEnableEXT enables_[1] = {VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT};
VkValidationFeaturesEXT features_ = {VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, nullptr, 1, enables_, 0, nullptr};
};
class GpuAVTest : public virtual VkLayerTest {
public:
void InitGpuAvFramework(std::vector<VkLayerSettingEXT> layer_settings = {}, bool safe_mode = true);
VkValidationFeaturesEXT GetGpuAvValidationFeatures();
};
class GpuAVGpuAVShaderSanitizer : public GpuAVTest {
public:
void SimpleZeroComputeTest(const char *shader, int source_type, const char *expected_error = nullptr, uint32_t error_count = 1);
};
class GpuAVBufferDeviceAddressTest : public GpuAVTest {
public:
void InitGpuVUBufferDeviceAddress(bool safe_mode = true);
};
class GpuAVDescriptorIndexingTest : public GpuAVTest {
public:
void InitGpuVUDescriptorIndexing(bool safe_mode = true);
};
class GpuAVMesh : public GpuAVTest {
public:
void InitBasicMeshAndTask(bool safe_mode = true);
};
class GpuAVDescriptorClassGeneralBuffer : public GpuAVTest {
public:
void ComputeStorageBufferTest(const char *shader, int source_type, VkDeviceSize buffer_size,
const char *expected_error = nullptr, uint32_t error_count = 1);
};
class GpuAVDescriptorClassGeneralBufferCoopMat : public GpuAVTest {
public:
void InitCooperativeMatrixKHR(bool safe_mode = true);
void BasicComputeTest(const char *shader, int source_type, VkDeviceSize buffer_size, const char *expected_error = nullptr,
uint32_t error_count = 1);
};
class GpuAVCopyMemoryIndirect : public GpuAVTest {
public:
void InitGpuAVCopyMemoryIndirect(bool safe_mode = true);
};
class GpuAVRayQueryTest : public GpuAVTest {
public:
void InitGpuAVRayQuery(std::vector<VkLayerSettingEXT> layer_settings = {});
};
class DebugPrintfTests : public VkLayerTest {
public:
void InitDebugPrintfFramework(void *p_next = nullptr, bool reserve_slot = false);
};
class AndroidExternalResolveTest : public VkLayerTest {
public:
void InitBasicAndroidExternalResolve();
bool nullColorAttachmentWithExternalFormatResolve;
};
class LegacyTest : public VkLayerTest {
public:
void CreateRenderPass();
};
class DescriptorBufferTest : public VkLayerTest {
public:
void InitBasicDescriptorBuffer(void *instance_pnext = nullptr);
VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer_properties = vku::InitStructHelper();
};
class DescriptorIndexingTest : public VkLayerTest {
public:
void ComputePipelineShaderTest(const char *shader, std::vector<VkDescriptorSetLayoutBinding> &bindings);
};
class DynamicRenderingTest : public VkLayerTest {
public:
void InitBasicDynamicRendering();
void InitBasicDynamicRenderingLocalRead();
VkRenderingInfo GetSimpleRenderingInfo();
VkRenderingInfo GetSimpleSuspendInfo();
VkRenderingInfo GetSimpleResumeInfo();
};
class DynamicStateTest : public VkLayerTest {
public:
void InitBasicExtendedDynamicState(); // enables VK_EXT_extended_dynamic_state
};
class ExternalMemorySyncTest : public VkLayerTest {
protected:
#ifdef VK_USE_PLATFORM_WIN32_KHR
using ExternalHandle = HANDLE;
#else
using ExternalHandle = int;
#endif
};
class DeviceGeneratedCommandsTest : public VkLayerTest {
public:
void InitBasicDeviceGeneratedCommands();
void SetPreProcessBuffer(VkGeneratedCommandsInfoEXT &generated_commands_info, void *pipeline_or_shader_object = nullptr);
std::unique_ptr<vkt::Buffer> pre_process_buffer_ = std::make_unique<vkt::Buffer>();
};
class GraphicsLibraryTest : public VkLayerTest {
public:
void InitBasicGraphicsLibrary();
};
class TileMemoryHeapTest : public VkLayerTest {
public:
};
class HostImageCopyTest : public VkLayerTest {
public:
void InitHostImageCopyTest();
bool CopyLayoutSupported(const std::vector<VkImageLayout> &copy_src_layouts, const std::vector<VkImageLayout> &copy_dst_layouts,
VkImageLayout layout);
std::vector<VkImageLayout> copy_src_layouts;
std::vector<VkImageLayout> copy_dst_layouts;
// Every test will use these, set the default most will use
uint32_t width = 32;
uint32_t height = 32;
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageCreateInfo image_ci;
};
class ImageTest : public VkLayerTest {
public:
VkImageCreateInfo DefaultImageInfo();
};
class ImageDrmTest : public VkLayerTest {
public:
void InitBasicImageDrm();
std::vector<uint64_t> GetFormatModifier(VkFormat format, VkFormatFeatureFlags2 features, uint32_t plane_count = 1);
};
class MeshTest : public virtual VkLayerTest {
public:
void InitBasicMeshAndTask();
};
class QueryTest : public VkLayerTest {
public:
bool HasZeroTimestampValidBits();
};
class RayTracingTest : public virtual VkLayerTest {
public:
void InitFrameworkForRayTracingTest(VkValidationFeaturesEXT *enabled_features = nullptr);
void NvInitFrameworkForRayTracingTest(VkPhysicalDeviceFeatures2KHR *features2 = nullptr,
VkValidationFeaturesEXT *enabled_features = nullptr);
};
class GpuAVRayTracingTest : public GpuAVTest, public RayTracingTest {};
class ShaderObjectTest : public virtual VkLayerTest {
public:
void InitBasicShaderObject(void *instance_pnext = nullptr);
void InitBasicMeshShaderObject(APIVersion target_api_version);
// Many tests just need a basic vert/frag shader
vkt::Shader m_vert_shader;
vkt::Shader m_frag_shader;
void CreateMinimalShaders();
};
class SyncObjectTest : public VkLayerTest {
protected:
#ifdef VK_USE_PLATFORM_WIN32_KHR
using ExternalHandle = HANDLE;
#else
using ExternalHandle = int;
#endif
};
class TensorTest : public VkLayerTest {
public:
void InitBasicTensor();
static VkTensorDescriptionARM DefaultDesc();
static VkTensorDescriptionARM TensorShaderDesc();
static VkTensorCreateInfoARM DefaultCreateInfo(VkTensorDescriptionARM *desc = nullptr);
};
class DataGraphTest : public VkLayerTest {
public:
void InitBasicDataGraph();
static void CheckSessionMemory(const vkt::DataGraphPipelineSession& session);
static std::vector<VkBindDataGraphPipelineSessionMemoryInfoARM> InitSessionBindInfo(const vkt::DataGraphPipelineSession& session, const std::vector<vkt::DeviceMemory>& device_mem);
static VkTensorDescriptionARM DefaultDesc();
static VkTensorDescriptionARM DefaultConstantTensorDesc();
static VkDataGraphPipelineConstantARM GetConstant(const VkTensorDescriptionARM &desc = defaultConstantTensorDesc);
static const std::string IncorrectSpirvMessage;
static const VkTensorDescriptionARM defaultConstantTensorDesc;
};
class WsiTest : public VkLayerTest {
protected:
// Find physical device group that contains physical device selected by the test framework
std::optional<VkPhysicalDeviceGroupProperties> FindPhysicalDeviceGroup();
};
class CooperativeMatrixTest : public VkLayerTest {
public:
void InitCooperativeMatrixKHR();
};
class ParentTest : public VkLayerTest {
public:
~ParentTest();
vkt::Device *m_second_device = nullptr;
};
template <typename T>
bool IsValidVkStruct(const T &s) {
return vku::GetSType<T>() == s.sType;
}
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);
VkFormat FindFormatWithoutFeatures(VkPhysicalDevice gpu, VkImageTiling tiling,
VkFormatFeatureFlags undesired_features = vvl::kNoIndex32);
VkFormat FindFormatWithoutFeatures2(VkPhysicalDevice gpu, VkImageTiling tiling, VkFormatFeatureFlags2 undesired_features);
void PrintAndroid(const char *c);