| /* |
| * Copyright (c) 2015-2019 The Khronos Group Inc. |
| * Copyright (c) 2015-2019 Valve Corporation |
| * Copyright (c) 2015-2019 LunarG, Inc. |
| * Copyright (c) 2015-2019 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 |
| * |
| * Author: Chia-I Wu <[email protected]> |
| * Author: Chris Forbes <[email protected]> |
| * Author: Courtney Goeltzenleuchter <[email protected]> |
| * Author: Mark Lobodzinski <[email protected]> |
| * Author: Mike Stroyan <[email protected]> |
| * Author: Tobin Ehlis <[email protected]> |
| * Author: Tony Barbour <[email protected]> |
| * Author: Cody Northrop <[email protected]> |
| * Author: Dave Houlton <[email protected]> |
| * Author: Jeremy Kniager <[email protected]> |
| * Author: Shannon McPherson <[email protected]> |
| * Author: John Zulauf <[email protected]> |
| */ |
| |
| #ifndef VKLAYERTEST_H |
| #define VKLAYERTEST_H |
| |
| #ifdef ANDROID |
| #include "vulkan_wrapper.h" |
| #else |
| #define NOMINMAX |
| #include <vulkan/vulkan.h> |
| #endif |
| |
| #include "layers/vk_device_profile_api_layer.h" |
| |
| #if defined(ANDROID) |
| #include <android/log.h> |
| #if defined(VALIDATION_APK) |
| #include <android_native_app_glue.h> |
| #endif |
| #endif |
| |
| #include "icd-spv.h" |
| #include "test_common.h" |
| #include "vk_layer_config.h" |
| #include "vk_format_utils.h" |
| #include "vkrenderframework.h" |
| #include "vk_typemap_helper.h" |
| #include "convert_to_renderpass2.h" |
| |
| #include <algorithm> |
| #include <cmath> |
| #include <functional> |
| #include <limits> |
| #include <memory> |
| #include <unordered_set> |
| |
| //-------------------------------------------------------------------------------------- |
| // Mesh and VertexFormat Data |
| //-------------------------------------------------------------------------------------- |
| |
| static const char kSkipPrefix[] = " TEST SKIPPED:"; |
| |
| enum BsoFailSelect { |
| BsoFailNone, |
| BsoFailLineWidth, |
| BsoFailDepthBias, |
| BsoFailViewport, |
| BsoFailScissor, |
| BsoFailBlend, |
| BsoFailDepthBounds, |
| BsoFailStencilReadMask, |
| BsoFailStencilWriteMask, |
| BsoFailStencilReference, |
| BsoFailCmdClearAttachments, |
| BsoFailIndexBuffer, |
| BsoFailIndexBufferBadSize, |
| BsoFailIndexBufferBadOffset, |
| BsoFailIndexBufferBadMapSize, |
| BsoFailIndexBufferBadMapOffset, |
| BsoFailLineStipple, |
| }; |
| |
| static const char bindStateMinimalShaderText[] = "#version 450\nvoid main() {}\n"; |
| |
| static const char bindStateVertShaderText[] = |
| "#version 450\n" |
| "void main() {\n" |
| " gl_Position = vec4(1);\n" |
| "}\n"; |
| |
| static const char bindStateVertPointSizeShaderText[] = |
| "#version 450\n" |
| "out gl_PerVertex {\n" |
| " vec4 gl_Position;\n" |
| " float gl_PointSize;\n" |
| "};\n" |
| "void main() {\n" |
| " gl_Position = vec4(1);\n" |
| " gl_PointSize = 1.0;\n" |
| "}\n"; |
| |
| static char const bindStateGeomShaderText[] = |
| "#version 450\n" |
| "layout(triangles) in;\n" |
| "layout(triangle_strip, max_vertices=3) out;\n" |
| "void main() {\n" |
| " gl_Position = vec4(1);\n" |
| " EmitVertex();\n" |
| "}\n"; |
| |
| static char const bindStateGeomPointSizeShaderText[] = |
| "#version 450\n" |
| "layout (points) in;\n" |
| "layout (points) out;\n" |
| "layout (max_vertices = 1) out;\n" |
| "void main() {\n" |
| " gl_Position = vec4(1);\n" |
| " gl_PointSize = 1.0;\n" |
| " EmitVertex();\n" |
| "}\n"; |
| |
| static const char bindStateTscShaderText[] = |
| "#version 450\n" |
| "layout(vertices=3) out;\n" |
| "void main() {\n" |
| " gl_TessLevelOuter[0] = gl_TessLevelOuter[1] = gl_TessLevelOuter[2] = 1;\n" |
| " gl_TessLevelInner[0] = 1;\n" |
| "}\n"; |
| |
| static const char bindStateTeshaderText[] = |
| "#version 450\n" |
| "layout(triangles, equal_spacing, cw) in;\n" |
| "void main() { gl_Position = vec4(1); }\n"; |
| |
| static const char bindStateFragShaderText[] = |
| "#version 450\n" |
| "layout(location = 0) out vec4 uFragColor;\n" |
| "void main(){\n" |
| " uFragColor = vec4(0,1,0,1);\n" |
| "}\n"; |
| |
| static const char bindStateFragSamplerShaderText[] = |
| "#version 450\n" |
| "layout(set=0, binding=0) uniform sampler2D s;\n" |
| "layout(location=0) out vec4 x;\n" |
| "void main(){\n" |
| " x = texture(s, vec2(1));\n" |
| "}\n"; |
| |
| static const char bindStateFragUniformShaderText[] = |
| "#version 450\n" |
| "layout(set=0) layout(binding=0) uniform foo { int x; int y; } bar;\n" |
| "layout(location=0) out vec4 x;\n" |
| "void main(){\n" |
| " x = vec4(bar.y);\n" |
| "}\n"; |
| |
| // Static arrays helper |
| template <class ElementT, size_t array_size> |
| size_t size(ElementT (&)[array_size]) { |
| return array_size; |
| } |
| |
| // Format search helper |
| 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); |
| |
| // Validation report callback prototype |
| VKAPI_ATTR VkBool32 VKAPI_CALL myDbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, |
| int32_t msgCode, const char *pLayerPrefix, const char *pMsg, void *pUserData); |
| |
| // Simple sane SamplerCreateInfo boilerplate |
| VkSamplerCreateInfo SafeSaneSamplerCreateInfo(); |
| |
| VkImageViewCreateInfo SafeSaneImageViewCreateInfo(VkImage image, VkFormat format, VkImageAspectFlags aspect_mask); |
| |
| VkImageViewCreateInfo SafeSaneImageViewCreateInfo(const VkImageObj &image, VkFormat format, VkImageAspectFlags aspect_mask); |
| |
| // Helper for checking createRenderPass2 support and adding related extensions. |
| bool CheckCreateRenderPass2Support(VkRenderFramework *renderFramework, std::vector<const char *> &device_extension_names); |
| |
| // Helper for checking descriptor_indexing support and adding related extensions. |
| bool CheckDescriptorIndexingSupportAndInitFramework(VkRenderFramework *renderFramework, |
| std::vector<const char *> &instance_extension_names, |
| std::vector<const char *> &device_extension_names, |
| VkValidationFeaturesEXT *features, void *userData); |
| |
| // 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); |
| } |
| |
| // ErrorMonitor Usage: |
| // |
| // Call SetDesiredFailureMsg with a string to be compared against all |
| // encountered log messages, or a validation error enum identifying |
| // desired error message. Passing NULL or VALIDATION_ERROR_MAX_ENUM |
| // will match all log messages. logMsg will return true for skipCall |
| // only if msg is matched or NULL. |
| // |
| // Call VerifyFound to determine if all desired failure messages |
| // were encountered. Call VerifyNotFound to determine if any unexpected |
| // failure was encountered. |
| class ErrorMonitor { |
| public: |
| ErrorMonitor(); |
| |
| ~ErrorMonitor(); |
| |
| // Set monitor to pristine state |
| void Reset(); |
| |
| // ErrorMonitor will look for an error message containing the specified string(s) |
| void SetDesiredFailureMsg(const VkFlags msgFlags, const std::string msg); |
| void SetDesiredFailureMsg(const VkFlags msgFlags, const char *const msgString); |
| |
| // ErrorMonitor will look for an error message containing the specified string(s) |
| template <typename Iter> |
| void SetDesiredFailureMsg(const VkFlags msgFlags, Iter iter, const Iter end) { |
| for (; iter != end; ++iter) { |
| SetDesiredFailureMsg(msgFlags, *iter); |
| } |
| } |
| |
| // Set an error that the error monitor will ignore. Do not use this function if you are creating a new test. |
| // TODO: This is stopgap to block new unexpected errors from being introduced. The long-term goal is to remove the use of this |
| // function and its definition. |
| void SetUnexpectedError(const char *const msg); |
| |
| VkBool32 CheckForDesiredMsg(const char *const msgString); |
| vector<string> GetOtherFailureMsgs() const; |
| VkDebugReportFlagsEXT GetMessageFlags() const; |
| bool AnyDesiredMsgFound() const; |
| bool AllDesiredMsgsFound() const; |
| void SetError(const char *const errorString); |
| void SetBailout(bool *bailout); |
| void DumpFailureMsgs() const; |
| |
| // Helpers |
| |
| // ExpectSuccess now takes an optional argument allowing a custom combination of debug flags |
| void ExpectSuccess(VkDebugReportFlagsEXT const message_flag_mask = VK_DEBUG_REPORT_ERROR_BIT_EXT); |
| |
| void VerifyFound(); |
| void VerifyNotFound(); |
| |
| private: |
| // TODO: This is stopgap to block new unexpected errors from being introduced. The long-term goal is to remove the use of this |
| // function and its definition. |
| bool IgnoreMessage(std::string const &msg) const; |
| |
| VkFlags message_flags_; |
| std::unordered_multiset<std::string> desired_message_strings_; |
| std::unordered_multiset<std::string> failure_message_strings_; |
| std::vector<std::string> ignore_message_strings_; |
| vector<string> other_messages_; |
| test_platform_thread_mutex mutex_; |
| bool *bailout_; |
| bool message_found_; |
| }; |
| |
| class VkLayerTest : public VkRenderFramework { |
| public: |
| void VKTriangleTest(BsoFailSelect failCase); |
| |
| void GenericDrawPreparation(VkCommandBufferObj *commandBuffer, VkPipelineObj &pipelineobj, VkDescriptorSetObj &descriptorSet, |
| BsoFailSelect failCase); |
| |
| void Init(VkPhysicalDeviceFeatures *features = nullptr, VkPhysicalDeviceFeatures2 *features2 = nullptr, |
| const VkCommandPoolCreateFlags flags = 0, void *instance_pnext = nullptr); |
| bool AddSurfaceInstanceExtension(); |
| bool AddSwapchainDeviceExtension(); |
| ErrorMonitor *Monitor(); |
| VkCommandBufferObj *CommandBuffer(); |
| |
| protected: |
| ErrorMonitor *m_errorMonitor; |
| uint32_t m_instance_api_version = 0; |
| uint32_t m_target_api_version = 0; |
| bool m_enableWSI; |
| |
| uint32_t SetTargetApiVersion(uint32_t target_api_version); |
| uint32_t DeviceValidationVersion(); |
| bool LoadDeviceProfileLayer( |
| PFN_vkSetPhysicalDeviceFormatPropertiesEXT &fpvkSetPhysicalDeviceFormatPropertiesEXT, |
| PFN_vkGetOriginalPhysicalDeviceFormatPropertiesEXT &fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT); |
| |
| VkLayerTest(); |
| ~VkLayerTest(); |
| }; |
| |
| class VkPositiveLayerTest : public VkLayerTest { |
| public: |
| protected: |
| }; |
| |
| class VkWsiEnabledLayerTest : public VkLayerTest { |
| public: |
| protected: |
| VkWsiEnabledLayerTest() { m_enableWSI = true; } |
| }; |
| |
| class VkBufferTest { |
| public: |
| enum eTestEnFlags { |
| eDoubleDelete, |
| eInvalidDeviceOffset, |
| eInvalidMemoryOffset, |
| eBindNullBuffer, |
| eBindFakeBuffer, |
| eFreeInvalidHandle, |
| eNone, |
| }; |
| |
| enum eTestConditions { eOffsetAlignment = 1 }; |
| |
| static bool GetTestConditionValid(VkDeviceObj *aVulkanDevice, eTestEnFlags aTestFlag, VkBufferUsageFlags aBufferUsage = 0); |
| // A constructor which performs validation tests within construction. |
| VkBufferTest(VkDeviceObj *aVulkanDevice, VkBufferUsageFlags aBufferUsage, eTestEnFlags aTestFlag = eNone); |
| ~VkBufferTest(); |
| bool GetBufferCurrent(); |
| const VkBuffer &GetBuffer(); |
| void TestDoubleDestroy(); |
| |
| protected: |
| bool AllocateCurrent; |
| bool BoundCurrent; |
| bool CreateCurrent; |
| bool InvalidDeleteEn; |
| |
| VkBuffer VulkanBuffer; |
| VkDevice VulkanDevice; |
| VkDeviceMemory VulkanMemory; |
| }; |
| |
| struct CreatePipelineHelper; |
| class VkVerticesObj { |
| public: |
| VkVerticesObj(VkDeviceObj *aVulkanDevice, unsigned aAttributeCount, unsigned aBindingCount, unsigned aByteStride, |
| VkDeviceSize aVertexCount, const float *aVerticies); |
| ~VkVerticesObj(); |
| bool AddVertexInputToPipe(VkPipelineObj &aPipelineObj); |
| bool AddVertexInputToPipeHelpr(CreatePipelineHelper *pipelineHelper); |
| void BindVertexBuffers(VkCommandBuffer aCommandBuffer, unsigned aOffsetCount = 0, VkDeviceSize *aOffsetList = nullptr); |
| |
| protected: |
| static uint32_t BindIdGenerator; |
| |
| bool BoundCurrent; |
| unsigned AttributeCount; |
| unsigned BindingCount; |
| uint32_t BindId; |
| |
| VkPipelineVertexInputStateCreateInfo PipelineVertexInputStateCreateInfo; |
| VkVertexInputAttributeDescription *VertexInputAttributeDescription; |
| VkVertexInputBindingDescription *VertexInputBindingDescription; |
| VkConstantBufferObj VulkanMemoryBuffer; |
| }; |
| |
| struct OneOffDescriptorSet { |
| VkDeviceObj *device_; |
| VkDescriptorPool pool_; |
| VkDescriptorSetLayoutObj layout_; |
| VkDescriptorSet set_; |
| typedef std::vector<VkDescriptorSetLayoutBinding> Bindings; |
| std::vector<VkDescriptorBufferInfo> buffer_infos; |
| std::vector<VkDescriptorImageInfo> image_infos; |
| std::vector<VkWriteDescriptorSet> descriptor_writes; |
| |
| OneOffDescriptorSet(VkDeviceObj *device, const Bindings &bindings, VkDescriptorSetLayoutCreateFlags layout_flags = 0, |
| void *layout_pnext = NULL, VkDescriptorPoolCreateFlags poolFlags = 0, void *allocate_pnext = NULL); |
| ~OneOffDescriptorSet(); |
| bool Initialized(); |
| void WriteDescriptorBufferInfo(int blinding, VkBuffer buffer, VkDeviceSize size, |
| VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); |
| void WriteDescriptorBufferView(int blinding, VkBufferView &buffer_view, |
| VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER); |
| void WriteDescriptorImageInfo(int blinding, VkImageView image_view, VkSampler sampler, |
| VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); |
| void UpdateDescriptorSets(); |
| }; |
| |
| template <typename T> |
| bool IsValidVkStruct(const T &s) { |
| return LvlTypeMap<T>::kSType == s.sType; |
| } |
| |
| // Helper class for tersely creating create pipeline tests |
| // |
| // Designed with minimal error checking to ensure easy error state creation |
| // See OneshotTest for typical usage |
| struct CreatePipelineHelper { |
| public: |
| std::vector<VkDescriptorSetLayoutBinding> dsl_bindings_; |
| std::unique_ptr<OneOffDescriptorSet> descriptor_set_; |
| std::vector<VkPipelineShaderStageCreateInfo> shader_stages_; |
| VkPipelineVertexInputStateCreateInfo vi_ci_ = {}; |
| VkPipelineInputAssemblyStateCreateInfo ia_ci_ = {}; |
| VkPipelineTessellationStateCreateInfo tess_ci_ = {}; |
| VkViewport viewport_ = {}; |
| VkRect2D scissor_ = {}; |
| VkPipelineViewportStateCreateInfo vp_state_ci_ = {}; |
| VkPipelineMultisampleStateCreateInfo pipe_ms_state_ci_ = {}; |
| VkPipelineLayoutCreateInfo pipeline_layout_ci_ = {}; |
| VkPipelineLayoutObj pipeline_layout_; |
| VkPipelineDynamicStateCreateInfo dyn_state_ci_ = {}; |
| VkPipelineRasterizationStateCreateInfo rs_state_ci_ = {}; |
| VkPipelineRasterizationLineStateCreateInfoEXT line_state_ci_ = {}; |
| VkPipelineColorBlendAttachmentState cb_attachments_ = {}; |
| VkPipelineColorBlendStateCreateInfo cb_ci_ = {}; |
| VkGraphicsPipelineCreateInfo gp_ci_ = {}; |
| VkPipelineCacheCreateInfo pc_ci_ = {}; |
| VkPipeline pipeline_ = VK_NULL_HANDLE; |
| VkPipelineCache pipeline_cache_ = VK_NULL_HANDLE; |
| std::unique_ptr<VkShaderObj> vs_; |
| std::unique_ptr<VkShaderObj> fs_; |
| VkLayerTest &layer_test_; |
| CreatePipelineHelper(VkLayerTest &test); |
| ~CreatePipelineHelper(); |
| |
| void InitDescriptorSetInfo(); |
| void InitInputAndVertexInfo(); |
| void InitMultisampleInfo(); |
| void InitPipelineLayoutInfo(); |
| void InitViewportInfo(); |
| void InitDynamicStateInfo(); |
| void InitShaderInfo(); |
| void InitRasterizationInfo(); |
| void InitLineRasterizationInfo(); |
| void InitBlendStateInfo(); |
| void InitGraphicsPipelineInfo(); |
| void InitPipelineCacheInfo(); |
| |
| // Not called by default during init_info |
| void InitTesselationState(); |
| |
| // TDB -- add control for optional and/or additional initialization |
| void InitInfo(); |
| void InitState(); |
| void LateBindPipelineInfo(); |
| VkResult CreateGraphicsPipeline(bool implicit_destroy = true, bool do_late_bind = true); |
| |
| // Helper function to create a simple test case (positive or negative) |
| // |
| // info_override can be any callable that takes a CreatePipelineHeper & |
| // flags, error can be any args accepted by "SetDesiredFailure". |
| template <typename Test, typename OverrideFunc, typename Error> |
| static void OneshotTest(Test &test, const OverrideFunc &info_override, const VkFlags flags, const std::vector<Error> &errors, |
| bool positive_test = false) { |
| CreatePipelineHelper helper(test); |
| helper.InitInfo(); |
| info_override(helper); |
| helper.InitState(); |
| |
| for (const auto &error : errors) test.Monitor()->SetDesiredFailureMsg(flags, error); |
| helper.CreateGraphicsPipeline(); |
| |
| if (positive_test) { |
| test.Monitor()->VerifyNotFound(); |
| } else { |
| test.Monitor()->VerifyFound(); |
| } |
| } |
| |
| template <typename Test, typename OverrideFunc, typename Error> |
| static void OneshotTest(Test &test, const OverrideFunc &info_override, const VkFlags flags, Error error, |
| bool positive_test = false) { |
| OneshotTest(test, info_override, flags, std::vector<Error>(1, error), positive_test); |
| } |
| }; |
| |
| struct CreateComputePipelineHelper { |
| public: |
| std::vector<VkDescriptorSetLayoutBinding> dsl_bindings_; |
| std::unique_ptr<OneOffDescriptorSet> descriptor_set_; |
| VkPipelineLayoutCreateInfo pipeline_layout_ci_ = {}; |
| VkPipelineLayoutObj pipeline_layout_; |
| VkComputePipelineCreateInfo cp_ci_ = {}; |
| VkPipelineCacheCreateInfo pc_ci_ = {}; |
| VkPipeline pipeline_ = VK_NULL_HANDLE; |
| VkPipelineCache pipeline_cache_ = VK_NULL_HANDLE; |
| std::unique_ptr<VkShaderObj> cs_; |
| VkLayerTest &layer_test_; |
| CreateComputePipelineHelper(VkLayerTest &test); |
| ~CreateComputePipelineHelper(); |
| |
| void InitDescriptorSetInfo(); |
| void InitPipelineLayoutInfo(); |
| void InitShaderInfo(); |
| void InitComputePipelineInfo(); |
| void InitPipelineCacheInfo(); |
| |
| // TDB -- add control for optional and/or additional initialization |
| void InitInfo(); |
| void InitState(); |
| void LateBindPipelineInfo(); |
| VkResult CreateComputePipeline(bool implicit_destroy = true, bool do_late_bind = true); |
| |
| // Helper function to create a simple test case (positive or negative) |
| // |
| // info_override can be any callable that takes a CreatePipelineHeper & |
| // flags, error can be any args accepted by "SetDesiredFailure". |
| template <typename Test, typename OverrideFunc, typename Error> |
| static void OneshotTest(Test &test, const OverrideFunc &info_override, const VkFlags flags, const std::vector<Error> &errors, |
| bool positive_test = false) { |
| CreateComputePipelineHelper helper(test); |
| helper.InitInfo(); |
| info_override(helper); |
| helper.InitState(); |
| |
| for (const auto &error : errors) test.Monitor()->SetDesiredFailureMsg(flags, error); |
| helper.CreateComputePipeline(); |
| |
| if (positive_test) { |
| test.Monitor()->VerifyNotFound(); |
| } else { |
| test.Monitor()->VerifyFound(); |
| } |
| } |
| |
| template <typename Test, typename OverrideFunc, typename Error> |
| static void OneshotTest(Test &test, const OverrideFunc &info_override, const VkFlags flags, Error error, |
| bool positive_test = false) { |
| OneshotTest(test, info_override, flags, std::vector<Error>(1, error), positive_test); |
| } |
| }; |
| |
| // Helper class for tersely creating create ray tracing pipeline tests |
| // |
| // Designed with minimal error checking to ensure easy error state creation |
| // See OneshotTest for typical usage |
| struct CreateNVRayTracingPipelineHelper { |
| public: |
| std::vector<VkDescriptorSetLayoutBinding> dsl_bindings_; |
| std::unique_ptr<OneOffDescriptorSet> descriptor_set_; |
| std::vector<VkPipelineShaderStageCreateInfo> shader_stages_; |
| VkPipelineLayoutCreateInfo pipeline_layout_ci_ = {}; |
| VkPipelineLayoutObj pipeline_layout_; |
| VkRayTracingPipelineCreateInfoNV rp_ci_ = {}; |
| VkPipelineCacheCreateInfo pc_ci_ = {}; |
| VkPipeline pipeline_ = VK_NULL_HANDLE; |
| VkPipelineCache pipeline_cache_ = VK_NULL_HANDLE; |
| std::vector<VkRayTracingShaderGroupCreateInfoNV> groups_; |
| std::unique_ptr<VkShaderObj> rgs_; |
| std::unique_ptr<VkShaderObj> chs_; |
| std::unique_ptr<VkShaderObj> mis_; |
| VkLayerTest &layer_test_; |
| CreateNVRayTracingPipelineHelper(VkLayerTest &test); |
| ~CreateNVRayTracingPipelineHelper(); |
| |
| static bool InitInstanceExtensions(VkLayerTest &test, std::vector<const char *> &instance_extension_names); |
| static bool InitDeviceExtensions(VkLayerTest &test, std::vector<const char *> &device_extension_names); |
| void InitShaderGroups(); |
| void InitDescriptorSetInfo(); |
| void InitPipelineLayoutInfo(); |
| void InitShaderInfo(); |
| void InitNVRayTracingPipelineInfo(); |
| void InitPipelineCacheInfo(); |
| void InitInfo(); |
| void InitState(); |
| void LateBindPipelineInfo(); |
| VkResult CreateNVRayTracingPipeline(bool implicit_destroy = true, bool do_late_bind = true); |
| |
| // Helper function to create a simple test case (positive or negative) |
| // |
| // info_override can be any callable that takes a CreateNVRayTracingPipelineHelper & |
| // flags, error can be any args accepted by "SetDesiredFailure". |
| template <typename Test, typename OverrideFunc, typename Error> |
| static void OneshotTest(Test &test, const OverrideFunc &info_override, const std::vector<Error> &errors, |
| const VkFlags flags = VK_DEBUG_REPORT_ERROR_BIT_EXT) { |
| CreateNVRayTracingPipelineHelper helper(test); |
| helper.InitInfo(); |
| info_override(helper); |
| helper.InitState(); |
| |
| for (const auto &error : errors) test.Monitor()->SetDesiredFailureMsg(flags, error); |
| helper.CreateNVRayTracingPipeline(); |
| test.Monitor()->VerifyFound(); |
| } |
| |
| template <typename Test, typename OverrideFunc, typename Error> |
| static void OneshotTest(Test &test, const OverrideFunc &info_override, Error error, |
| const VkFlags flags = VK_DEBUG_REPORT_ERROR_BIT_EXT) { |
| OneshotTest(test, info_override, std::vector<Error>(1, error), flags); |
| } |
| |
| template <typename Test, typename OverrideFunc> |
| static void OneshotPositiveTest(Test &test, const OverrideFunc &info_override, |
| const VkDebugReportFlagsEXT message_flag_mask = VK_DEBUG_REPORT_ERROR_BIT_EXT) { |
| CreateNVRayTracingPipelineHelper helper(test); |
| helper.InitInfo(); |
| info_override(helper); |
| helper.InitState(); |
| |
| test.Monitor()->ExpectSuccess(message_flag_mask); |
| ASSERT_VK_SUCCESS(helper.CreateNVRayTracingPipeline()); |
| test.Monitor()->VerifyNotFound(); |
| } |
| }; |
| |
| namespace chain_util { |
| template <typename T> |
| T Init(const void *pnext_in = nullptr) { |
| T pnext_obj = {}; |
| pnext_obj.sType = LvlTypeMap<T>::kSType; |
| pnext_obj.pNext = pnext_in; |
| return pnext_obj; |
| } |
| |
| class ExtensionChain { |
| const void *head_ = nullptr; |
| typedef std::function<bool(const char *)> AddIfFunction; |
| AddIfFunction add_if_; |
| typedef std::vector<const char *> List; |
| List *list_; |
| |
| public: |
| template <typename F> |
| ExtensionChain(F &add_if, List *list) : add_if_(add_if), list_(list) {} |
| |
| template <typename T> |
| void Add(const char *name, T &obj) { |
| if (add_if_(name)) { |
| if (list_) { |
| list_->push_back(name); |
| } |
| obj.pNext = head_; |
| head_ = &obj; |
| } |
| } |
| |
| const void *Head() const; |
| }; |
| } // namespace chain_util |
| |
| // PushDescriptorProperties helper |
| VkPhysicalDevicePushDescriptorPropertiesKHR GetPushDescriptorProperties(VkInstance instance, VkPhysicalDevice gpu); |
| |
| // Subgroup properties helper |
| VkPhysicalDeviceSubgroupProperties GetSubgroupProperties(VkInstance instance, VkPhysicalDevice gpu); |
| |
| class BarrierQueueFamilyTestHelper { |
| public: |
| struct QueueFamilyObjs { |
| uint32_t index; |
| // We would use std::unique_ptr, but this triggers a compiler error on older compilers |
| VkQueueObj *queue = nullptr; |
| VkCommandPoolObj *command_pool = nullptr; |
| VkCommandBufferObj *command_buffer = nullptr; |
| VkCommandBufferObj *command_buffer2 = nullptr; |
| ~QueueFamilyObjs(); |
| void Init(VkDeviceObj *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(); |
| }; |
| |
| BarrierQueueFamilyTestHelper(Context *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); |
| |
| QueueFamilyObjs *GetQueueFamilyInfo(Context *context, uint32_t qfi); |
| |
| enum Modifier { |
| NONE, |
| DOUBLE_RECORD, |
| DOUBLE_COMMAND_BUFFER, |
| }; |
| |
| void operator()(std::string img_err, std::string buf_err = "", uint32_t src = VK_QUEUE_FAMILY_IGNORED, |
| uint32_t dst = VK_QUEUE_FAMILY_IGNORED, bool positive = false, |
| uint32_t queue_family_index = kInvalidQueueFamily, Modifier mod = Modifier::NONE); |
| |
| static const uint32_t kInvalidQueueFamily = UINT32_MAX; |
| Context *context_; |
| VkImageObj image_; |
| VkImageMemoryBarrier image_barrier_; |
| VkBufferObj buffer_; |
| VkBufferMemoryBarrier 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 thread_data_struct { |
| VkCommandBuffer commandBuffer; |
| VkDevice device; |
| VkEvent event; |
| bool bailout; |
| }; |
| |
| extern "C" void *AddToCommandBuffer(void *arg); |
| #endif // GTEST_IS_THREADSAFE |
| |
| extern "C" void *ReleaseNullFence(void *arg); |
| |
| void TestRenderPassCreate(ErrorMonitor *error_monitor, const VkDevice device, const VkRenderPassCreateInfo *create_info, |
| bool rp2_supported, const char *rp1_vuid, const char *rp2_vuid); |
| void PositiveTestRenderPassCreate(ErrorMonitor *error_monitor, const VkDevice device, const VkRenderPassCreateInfo *create_info, |
| bool rp2_supported); |
| void TestRenderPass2KHRCreate(ErrorMonitor *error_monitor, const VkDevice device, const VkRenderPassCreateInfo2KHR *create_info, |
| const char *rp2_vuid); |
| 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, VkCommandBufferObj *cb, VkPipelineStageFlags src_stages, |
| VkPipelineStageFlags dst_stages, const VkBufferMemoryBarrier *buf_barrier, |
| const VkImageMemoryBarrier *img_barrier); |
| |
| void ValidOwnershipTransfer(ErrorMonitor *monitor, VkCommandBufferObj *cb_from, VkCommandBufferObj *cb_to, |
| VkPipelineStageFlags src_stages, VkPipelineStageFlags dst_stages, |
| const VkBufferMemoryBarrier *buf_barrier, const VkImageMemoryBarrier *img_barrier); |
| |
| VkResult GPDIFPHelper(VkPhysicalDevice dev, const VkImageCreateInfo *ci, VkImageFormatProperties *limits = nullptr); |
| |
| VkFormat FindFormatLinearWithoutMips(VkPhysicalDevice gpu, VkImageCreateInfo image_ci); |
| |
| bool FindFormatWithoutSamples(VkPhysicalDevice gpu, VkImageCreateInfo &image_ci); |
| |
| bool FindUnsupportedImage(VkPhysicalDevice gpu, VkImageCreateInfo &image_ci); |
| |
| VkFormat FindFormatWithoutFeatures(VkPhysicalDevice gpu, VkImageTiling tiling, |
| VkFormatFeatureFlags undesired_features = UINT32_MAX); |
| |
| void NegHeightViewportTests(VkDeviceObj *m_device, VkCommandBufferObj *m_commandBuffer, ErrorMonitor *m_errorMonitor); |
| |
| void CreateSamplerTest(VkLayerTest &test, const VkSamplerCreateInfo *pCreateInfo, std::string code = ""); |
| |
| void CreateBufferTest(VkLayerTest &test, const VkBufferCreateInfo *pCreateInfo, std::string code = ""); |
| |
| void CreateImageTest(VkLayerTest &test, const VkImageCreateInfo *pCreateInfo, std::string code = ""); |
| |
| void CreateBufferViewTest(VkLayerTest &test, const VkBufferViewCreateInfo *pCreateInfo, const std::vector<std::string> &codes); |
| |
| void CreateImageViewTest(VkLayerTest &test, const VkImageViewCreateInfo *pCreateInfo, std::string code = ""); |
| |
| void print_android(const char *c); |
| #endif // VKLAYERTEST_H |