| /* |
| * Copyright (c) 2015-2022 The Khronos Group Inc. |
| * Copyright (c) 2015-2022 Valve Corporation |
| * Copyright (c) 2015-2022 LunarG, Inc. |
| * Copyright (c) 2022 NVIDIA CORPORATION. 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 |
| * |
| * Author: Rodrigo Locatti <rlocatti@nvidia.com> |
| */ |
| |
| #include <chrono> |
| #include <thread> |
| |
| #include "cast_utils.h" |
| #include "layer_validation_tests.h" |
| |
| // Tests for NVIDIA-specific best practices |
| const char *kEnableNVIDIAValidation = "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA"; |
| |
| static constexpr float defaultQueuePriority = 0.0f; |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, PageableDeviceLocalMemory) { |
| AddRequiredExtensions(VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME); |
| InitBestPracticesFramework(kEnableNVIDIAValidation); |
| |
| if (!AreRequiredExtensionsEnabled()) { |
| GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported"; |
| } |
| |
| VkDeviceQueueCreateInfo queue_ci = LvlInitStruct<VkDeviceQueueCreateInfo>(); |
| queue_ci.queueCount = 1; |
| queue_ci.pQueuePriorities = &defaultQueuePriority; |
| |
| VkDeviceCreateInfo device_ci = LvlInitStruct<VkDeviceCreateInfo>(); |
| device_ci.queueCreateInfoCount = 1; |
| device_ci.pQueueCreateInfos = &queue_ci; |
| |
| VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT pageable = LvlInitStruct<VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT>(); |
| pageable.pageableDeviceLocalMemory = VK_TRUE; |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-CreateDevice-PageableDeviceLocalMemory"); |
| VkDevice test_device = VK_NULL_HANDLE; |
| VkResult err = vk::CreateDevice(gpu(), &device_ci, nullptr, &test_device); |
| m_errorMonitor->VerifyFound(); |
| if (err == VK_SUCCESS) { |
| vk::DestroyDevice(test_device, nullptr); |
| } |
| } |
| |
| // Now enable the expected features |
| device_ci.enabledExtensionCount = m_device_extension_names.size(); |
| device_ci.ppEnabledExtensionNames = m_device_extension_names.data(); |
| device_ci.pNext = &pageable; |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-CreateDevice-PageableDeviceLocalMemory"); |
| vk_testing::Device test_device(gpu()); |
| test_device.init(device_ci); |
| m_errorMonitor->Finish(); |
| } |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, TilingLinear) { |
| InitBestPracticesFramework(kEnableNVIDIAValidation); |
| InitState(); |
| |
| VkImageCreateInfo image_ci = LvlInitStruct<VkImageCreateInfo>(); |
| image_ci.imageType = VK_IMAGE_TYPE_2D; |
| image_ci.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32; |
| image_ci.extent = { 512, 512, 1 }; |
| image_ci.mipLevels = 1; |
| image_ci.arrayLayers = 1; |
| image_ci.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_ci.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_ci.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-CreateImage-TilingLinear"); |
| vk_testing::Image image(*m_device, image_ci, vk_testing::no_mem); |
| m_errorMonitor->Finish(); |
| } |
| |
| image_ci.tiling = VK_IMAGE_TILING_LINEAR; |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-CreateImage-TilingLinear"); |
| vk_testing::Image image(*m_device, image_ci, vk_testing::no_mem); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, Depth32Format) { |
| InitBestPracticesFramework(kEnableNVIDIAValidation); |
| InitState(); |
| |
| VkImageCreateInfo image_ci = LvlInitStruct<VkImageCreateInfo>(); |
| image_ci.imageType = VK_IMAGE_TYPE_2D; |
| // This should be VK_FORMAT_D24_UNORM_S8_UINT, but that's not a required format. |
| image_ci.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32; |
| image_ci.extent = { 512, 512, 1 }; |
| image_ci.mipLevels = 1; |
| image_ci.arrayLayers = 1; |
| image_ci.samples = VK_SAMPLE_COUNT_1_BIT; |
| image_ci.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_ci.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-CreateImage-Depth32Format"); |
| vk_testing::Image image(*m_device, image_ci, vk_testing::no_mem); |
| m_errorMonitor->Finish(); |
| } |
| |
| VkFormat formats[] = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT }; |
| |
| for (VkFormat format : formats) { |
| image_ci.format = format; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-CreateImage-Depth32Format"); |
| vk_testing::Image image(*m_device, image_ci, vk_testing::no_mem); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, QueueBindSparse_NotAsync) { |
| InitBestPracticesFramework(kEnableNVIDIAValidation); |
| InitState(); |
| |
| if (!m_device->phy().features().sparseBinding) { |
| GTEST_SKIP() << "Test requires sparseBinding"; |
| } |
| |
| VkDeviceQueueCreateInfo general_queue_ci = LvlInitStruct<VkDeviceQueueCreateInfo>(); |
| general_queue_ci.queueFamilyIndex = m_device->QueueFamilyMatching(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_SPARSE_BINDING_BIT, 0); |
| general_queue_ci.queueCount = 1; |
| general_queue_ci.pQueuePriorities = &defaultQueuePriority; |
| |
| VkDeviceQueueCreateInfo transfer_queue_ci = LvlInitStruct<VkDeviceQueueCreateInfo>(); |
| transfer_queue_ci.queueFamilyIndex = m_device->QueueFamilyMatching(VK_QUEUE_TRANSFER_BIT | VK_QUEUE_SPARSE_BINDING_BIT, |
| VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT); |
| transfer_queue_ci.queueCount = 1; |
| transfer_queue_ci.pQueuePriorities = &defaultQueuePriority; |
| |
| if (general_queue_ci.queueFamilyIndex == UINT32_MAX || transfer_queue_ci.queueFamilyIndex == UINT32_MAX) { |
| GTEST_SKIP() << "Test requires a general and a transfer queue"; |
| } |
| |
| VkDeviceQueueCreateInfo queue_cis[2] = { |
| general_queue_ci, |
| transfer_queue_ci, |
| }; |
| uint32_t queue_family_indices[] = { |
| general_queue_ci.queueFamilyIndex, |
| transfer_queue_ci.queueFamilyIndex, |
| }; |
| |
| VkPhysicalDeviceFeatures features = {}; |
| features.sparseBinding = VK_TRUE; |
| |
| VkDeviceCreateInfo device_ci = LvlInitStruct<VkDeviceCreateInfo>(); |
| device_ci.queueCreateInfoCount = 2; |
| device_ci.pQueueCreateInfos = queue_cis; |
| device_ci.pEnabledFeatures = &features; |
| |
| vk_testing::Device test_device(gpu()); |
| test_device.init(device_ci); |
| |
| VkQueue graphics_queue = VK_NULL_HANDLE; |
| VkQueue transfer_queue = VK_NULL_HANDLE; |
| vk::GetDeviceQueue(test_device.handle(), general_queue_ci.queueFamilyIndex, 0, &graphics_queue); |
| vk::GetDeviceQueue(test_device.handle(), transfer_queue_ci.queueFamilyIndex, 0, &transfer_queue); |
| |
| VkBufferCreateInfo sparse_buffer_ci = LvlInitStruct<VkBufferCreateInfo>(); |
| sparse_buffer_ci.flags = VK_BUFFER_CREATE_SPARSE_BINDING_BIT; |
| sparse_buffer_ci.size = 0x10000; |
| sparse_buffer_ci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| sparse_buffer_ci.sharingMode = VK_SHARING_MODE_CONCURRENT; |
| sparse_buffer_ci.queueFamilyIndexCount = 2; |
| sparse_buffer_ci.pQueueFamilyIndices = queue_family_indices; |
| |
| vk_testing::Buffer sparse_buffer(test_device, sparse_buffer_ci, vk_testing::no_mem); |
| |
| const VkMemoryRequirements memory_requirements = sparse_buffer.memory_requirements(); |
| ASSERT_NE(memory_requirements.memoryTypeBits, 0); |
| |
| // Find first valid bit, whatever it is |
| uint32_t memory_type_index = 0; |
| while (((memory_requirements.memoryTypeBits >> memory_type_index) & 1) == 0) { |
| ++memory_type_index; |
| } |
| |
| VkMemoryAllocateInfo memory_ai = LvlInitStruct<VkMemoryAllocateInfo>(); |
| memory_ai.allocationSize = memory_requirements.size; |
| memory_ai.memoryTypeIndex = memory_type_index; |
| |
| vk_testing::DeviceMemory sparse_memory(test_device, memory_ai); |
| |
| VkSparseMemoryBind bind = {}; |
| bind.resourceOffset = 0; |
| bind.size = sparse_buffer_ci.size; |
| bind.memory = sparse_memory.handle(); |
| bind.memoryOffset = 0; |
| bind.flags = 0; |
| |
| VkSparseBufferMemoryBindInfo sparse_buffer_bind = {}; |
| sparse_buffer_bind.buffer = sparse_buffer.handle(); |
| sparse_buffer_bind.bindCount = 1; |
| sparse_buffer_bind.pBinds = &bind; |
| |
| VkBindSparseInfo bind_info = LvlInitStruct<VkBindSparseInfo>(); |
| bind_info.bufferBindCount = 1; |
| bind_info.pBufferBinds = &sparse_buffer_bind; |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-QueueBindSparse-NotAsync"); |
| vk::QueueBindSparse(transfer_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->Finish(); |
| } |
| |
| test_device.wait(); |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-QueueBindSparse-NotAsync"); |
| vk::QueueBindSparse(graphics_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, AccelerationStructure_NotAsync) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| InitBestPracticesFramework(kEnableNVIDIAValidation); |
| |
| if (IsDriver(VK_DRIVER_ID_AMD_PROPRIETARY)) { |
| GTEST_SKIP() << "Test is crashing on AMD hardware for unknown reasons."; |
| } |
| if (DeviceValidationVersion() < VK_API_VERSION_1_1) { |
| GTEST_SKIP() << "Vulkan >= 1.1 required"; |
| } |
| if (!AreRequiredExtensionsEnabled()) { |
| GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported"; |
| } |
| InitState(); |
| |
| VkDeviceQueueCreateInfo general_queue_ci = LvlInitStruct<VkDeviceQueueCreateInfo>(); |
| general_queue_ci.queueFamilyIndex = m_device->QueueFamilyMatching(VK_QUEUE_GRAPHICS_BIT, 0); |
| general_queue_ci.queueCount = 1; |
| general_queue_ci.pQueuePriorities = &defaultQueuePriority; |
| |
| VkDeviceQueueCreateInfo compute_queue_ci = LvlInitStruct<VkDeviceQueueCreateInfo>(); |
| compute_queue_ci.queueFamilyIndex = m_device->QueueFamilyMatching(VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT); |
| compute_queue_ci.queueCount = 1; |
| compute_queue_ci.pQueuePriorities = &defaultQueuePriority; |
| |
| if (general_queue_ci.queueFamilyIndex == UINT32_MAX || compute_queue_ci.queueFamilyIndex == UINT32_MAX) { |
| // There's no asynchronous compute queue, skip. |
| return; |
| } |
| |
| VkDeviceQueueCreateInfo queue_cis[2] = { |
| general_queue_ci, |
| compute_queue_ci, |
| }; |
| uint32_t queue_family_indices[] = { |
| general_queue_ci.queueFamilyIndex, |
| compute_queue_ci.queueFamilyIndex, |
| }; |
| |
| VkPhysicalDeviceAccelerationStructureFeaturesKHR acceleration_structures_features = LvlInitStruct<VkPhysicalDeviceAccelerationStructureFeaturesKHR>(); |
| acceleration_structures_features.accelerationStructure = VK_TRUE; |
| |
| VkPhysicalDeviceBufferDeviceAddressFeaturesEXT buffer_device_address_features = LvlInitStruct<VkPhysicalDeviceBufferDeviceAddressFeaturesEXT>(); |
| buffer_device_address_features.pNext = &acceleration_structures_features; |
| buffer_device_address_features.bufferDeviceAddress = VK_TRUE; |
| |
| VkDeviceCreateInfo device_ci = LvlInitStruct<VkDeviceCreateInfo>(); |
| device_ci.pNext = &buffer_device_address_features; |
| device_ci.queueCreateInfoCount = 2; |
| device_ci.pQueueCreateInfos = queue_cis; |
| device_ci.enabledExtensionCount = m_device_extension_names.size(); |
| device_ci.ppEnabledExtensionNames = m_device_extension_names.data(); |
| |
| vk_testing::Device test_device(gpu()); |
| test_device.init(device_ci); |
| |
| VkQueue graphics_queue = VK_NULL_HANDLE; |
| VkQueue transfer_queue = VK_NULL_HANDLE; |
| vk::GetDeviceQueue(test_device.handle(), general_queue_ci.queueFamilyIndex, 0, &graphics_queue); |
| vk::GetDeviceQueue(test_device.handle(), compute_queue_ci.queueFamilyIndex, 0, &transfer_queue); |
| |
| VkBufferCreateInfo acceleration_structure_buffer_ci = LvlInitStruct<VkBufferCreateInfo>(); |
| acceleration_structure_buffer_ci.size = 0x10000; |
| acceleration_structure_buffer_ci.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR; |
| |
| VkBufferCreateInfo scratch_buffer_ci = LvlInitStruct<VkBufferCreateInfo>(); |
| scratch_buffer_ci.size = 1ULL << 20; |
| scratch_buffer_ci.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; |
| |
| vk_testing::Buffer acceleration_structure_buffer(test_device, acceleration_structure_buffer_ci); |
| vk_testing::Buffer scratch_buffer(test_device, scratch_buffer_ci); |
| |
| auto vkGetBufferDeviceAddressKHR = |
| (PFN_vkGetBufferDeviceAddress)vk::GetDeviceProcAddr(m_device->device(), "vkGetBufferDeviceAddressKHR"); |
| ASSERT_TRUE(vkGetBufferDeviceAddressKHR != nullptr); |
| |
| VkBufferDeviceAddressInfo scratch_buffer_device_address_info = LvlInitStruct<VkBufferDeviceAddressInfo>(); |
| scratch_buffer_device_address_info.buffer = scratch_buffer.handle(); |
| VkDeviceAddress scratch_address = vkGetBufferDeviceAddressKHR(test_device.handle(), &scratch_buffer_device_address_info); |
| |
| VkAccelerationStructureCreateInfoKHR acceleration_structure_ci = LvlInitStruct<VkAccelerationStructureCreateInfoKHR>(); |
| acceleration_structure_ci.buffer = acceleration_structure_buffer.handle(); |
| acceleration_structure_ci.offset = 0; |
| acceleration_structure_ci.size = acceleration_structure_buffer_ci.size; |
| acceleration_structure_ci.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; |
| acceleration_structure_ci.deviceAddress = 0; |
| |
| vk_testing::AccelerationStructureKHR acceleration_structure(test_device, acceleration_structure_ci); |
| |
| VkAccelerationStructureGeometryTrianglesDataKHR triangle_data = LvlInitStruct<VkAccelerationStructureGeometryTrianglesDataKHR>(); |
| triangle_data.vertexFormat = VK_FORMAT_A8B8G8R8_UNORM_PACK32; |
| triangle_data.vertexData.deviceAddress = 0; |
| triangle_data.vertexStride = 0; |
| triangle_data.maxVertex = 3; |
| triangle_data.indexType = VK_INDEX_TYPE_UINT16; |
| triangle_data.indexData.deviceAddress = 0; |
| triangle_data.transformData.deviceAddress = 0; |
| |
| VkAccelerationStructureGeometryKHR geometry = LvlInitStruct<VkAccelerationStructureGeometryKHR>(); |
| geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; |
| geometry.geometry.triangles = triangle_data; |
| geometry.flags = 0; |
| |
| VkAccelerationStructureBuildGeometryInfoKHR geometry_info = LvlInitStruct<VkAccelerationStructureBuildGeometryInfoKHR>(); |
| geometry_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; |
| geometry_info.flags = 0; |
| geometry_info.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; |
| geometry_info.srcAccelerationStructure = VK_NULL_HANDLE; |
| geometry_info.dstAccelerationStructure = acceleration_structure.handle(); |
| geometry_info.geometryCount = 1; |
| geometry_info.pGeometries = &geometry; |
| geometry_info.ppGeometries = nullptr; |
| geometry_info.scratchData.deviceAddress = scratch_address; |
| |
| VkAccelerationStructureBuildRangeInfoKHR build_range_info = {}; |
| build_range_info.primitiveCount = 1; |
| build_range_info.primitiveOffset = 0; |
| build_range_info.firstVertex = 0; |
| build_range_info.transformOffset = 0; |
| |
| VkAccelerationStructureBuildRangeInfoKHR *p_build_range_info = &build_range_info; |
| |
| auto vkCmdBuildAccelerationStructuresKHR = reinterpret_cast<PFN_vkCmdBuildAccelerationStructuresKHR>( |
| vk::GetDeviceProcAddr(test_device.handle(), "vkCmdBuildAccelerationStructuresKHR")); |
| ASSERT_NE(vkCmdBuildAccelerationStructuresKHR, nullptr); |
| |
| for (uint32_t queue_family_index : queue_family_indices) { |
| VkCommandPoolCreateInfo command_pool_ci = LvlInitStruct<VkCommandPoolCreateInfo>(); |
| command_pool_ci.queueFamilyIndex = queue_family_index; |
| vk_testing::CommandPool command_pool(test_device, command_pool_ci); |
| |
| VkCommandBufferAllocateInfo command_buffer_ai = LvlInitStruct<VkCommandBufferAllocateInfo>(); |
| command_buffer_ai.commandPool = command_pool.handle(); |
| command_buffer_ai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
| command_buffer_ai.commandBufferCount = 1; |
| |
| vk_testing::CommandBuffer command_buffer(test_device, command_buffer_ai); |
| VkCommandBufferBeginInfo command_buffer_bi = LvlInitStruct<VkCommandBufferBeginInfo>(); |
| command_buffer_bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
| command_buffer.begin(&command_buffer_bi); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-AccelerationStructure-NotAsync"); |
| vkCmdBuildAccelerationStructuresKHR(command_buffer.handle(), 1, &geometry_info, &p_build_range_info); |
| |
| if (queue_family_index == compute_queue_ci.queueFamilyIndex) { |
| m_errorMonitor->Finish(); |
| } else { |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| command_buffer.end(); |
| } |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, AllocateMemory_SetPriority) { |
| InitBestPracticesFramework(kEnableNVIDIAValidation); |
| InitState(); |
| |
| VkMemoryAllocateInfo memory_ai = LvlInitStruct<VkMemoryAllocateInfo>(); |
| memory_ai.allocationSize = 0x100000; |
| memory_ai.memoryTypeIndex = 0; |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-AllocateMemory-SetPriority"); |
| vk_testing::DeviceMemory memory(*m_device, memory_ai); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| VkMemoryPriorityAllocateInfoEXT priority = LvlInitStruct<VkMemoryPriorityAllocateInfoEXT>(); |
| priority.priority = 0.5f; |
| memory_ai.pNext = &priority; |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-AllocateMemory-SetPriority"); |
| vk_testing::DeviceMemory memory(*m_device, memory_ai); |
| m_errorMonitor->Finish(); |
| } |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, AllocateMemory_ReuseAllocations) { |
| InitBestPracticesFramework(kEnableNVIDIAValidation); |
| InitState(); |
| |
| VkMemoryAllocateInfo memory_ai = LvlInitStruct<VkMemoryAllocateInfo>(); |
| memory_ai.allocationSize = 0x100000; |
| memory_ai.memoryTypeIndex = 0; |
| |
| VkMemoryPriorityAllocateInfoEXT priority = LvlInitStruct<VkMemoryPriorityAllocateInfoEXT>(); |
| priority.priority = 0.5f; |
| memory_ai.pNext = &priority; |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-AllocateMemory-ReuseAllocations"); |
| { |
| vk_testing::DeviceMemory memory(*m_device, memory_ai); |
| } |
| |
| std::this_thread::sleep_for(std::chrono::seconds{6}); |
| |
| { |
| vk_testing::DeviceMemory memory(*m_device, memory_ai); |
| } |
| |
| m_errorMonitor->Finish(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-AllocateMemory-ReuseAllocations"); |
| |
| { |
| vk_testing::DeviceMemory memory(*m_device, memory_ai); |
| } |
| |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, BindMemory_NoPriority) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| InitBestPracticesFramework(kEnableNVIDIAValidation); |
| |
| if (DeviceValidationVersion() < VK_API_VERSION_1_1) { |
| GTEST_SKIP() << "Vulkan >= 1.1 required"; |
| } |
| if (!AreRequiredExtensionsEnabled()) { |
| GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported"; |
| } |
| InitState(); |
| |
| VkDeviceQueueCreateInfo queue_ci = LvlInitStruct<VkDeviceQueueCreateInfo>(); |
| queue_ci.queueFamilyIndex = 0; |
| queue_ci.queueCount = 1; |
| queue_ci.pQueuePriorities = &defaultQueuePriority; |
| |
| VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT pageable_features = LvlInitStruct<VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT>(); |
| pageable_features.pNext = nullptr; |
| pageable_features.pageableDeviceLocalMemory = VK_TRUE; |
| |
| VkPhysicalDeviceMaintenance4Features maintenance4_features = LvlInitStruct<VkPhysicalDeviceMaintenance4Features>(); |
| maintenance4_features.pNext = &pageable_features; |
| maintenance4_features.maintenance4 = VK_TRUE; |
| |
| VkDeviceCreateInfo device_ci = LvlInitStruct<VkDeviceCreateInfo>(); |
| device_ci.pNext = &maintenance4_features; |
| device_ci.queueCreateInfoCount = 1; |
| device_ci.pQueueCreateInfos = &queue_ci; |
| device_ci.enabledExtensionCount = m_device_extension_names.size(); |
| device_ci.ppEnabledExtensionNames = m_device_extension_names.data(); |
| |
| vk_testing::Device test_device(gpu()); |
| test_device.init(device_ci); |
| |
| VkBufferCreateInfo buffer_ci = LvlInitStruct<VkBufferCreateInfo>(); |
| buffer_ci.flags = 0; |
| buffer_ci.size = 0x100000; |
| buffer_ci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| buffer_ci.queueFamilyIndexCount = 0; |
| buffer_ci.pQueueFamilyIndices = nullptr; |
| |
| vk_testing::Buffer buffer_a(test_device, buffer_ci, vk_testing::no_mem); |
| vk_testing::Buffer buffer_b(test_device, buffer_ci, vk_testing::no_mem); |
| |
| const VkMemoryRequirements memory_requirements = buffer_a.memory_requirements(); |
| ASSERT_NE(memory_requirements.memoryTypeBits, 0); |
| |
| // Find first valid bit, whatever it is |
| uint32_t memory_type_index = 0; |
| while (((memory_requirements.memoryTypeBits >> memory_type_index) & 1) == 0) { |
| ++memory_type_index; |
| } |
| |
| VkMemoryAllocateInfo memory_ai = LvlInitStruct<VkMemoryAllocateInfo>(); |
| memory_ai.allocationSize = memory_requirements.size; |
| memory_ai.memoryTypeIndex = memory_type_index; |
| |
| vk_testing::DeviceMemory memory(test_device, memory_ai); |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-BindMemory-NoPriority"); |
| vk::BindBufferMemory(test_device.handle(), buffer_a.handle(), memory.handle(), 0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| auto vkSetDeviceMemoryPriorityEXT = reinterpret_cast<PFN_vkSetDeviceMemoryPriorityEXT>( |
| vk::GetDeviceProcAddr(test_device.handle(), "vkSetDeviceMemoryPriorityEXT")); |
| vkSetDeviceMemoryPriorityEXT(test_device.handle(), memory.handle(), 0.5f); |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-BindMemory-NoPriority"); |
| vk::BindBufferMemory(test_device.handle(), buffer_b.handle(), memory.handle(), 0); |
| m_errorMonitor->Finish(); |
| } |
| } |
| |
| static VkDescriptorSetLayoutBinding CreateSingleDescriptorBinding(VkDescriptorType type, uint32_t binding) { |
| VkDescriptorSetLayoutBinding layout_binding = {}; |
| layout_binding.binding = binding; |
| layout_binding.descriptorType = type; |
| layout_binding.descriptorCount = 1; |
| layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; |
| layout_binding.pImmutableSamplers = nullptr; |
| return layout_binding; |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, CreatePipelineLayout_SeparateSampler) { |
| InitBestPracticesFramework(kEnableNVIDIAValidation); |
| InitState(); |
| |
| VkDescriptorSetLayoutBinding separate_bindings[] = { |
| CreateSingleDescriptorBinding(VK_DESCRIPTOR_TYPE_SAMPLER, 0), |
| CreateSingleDescriptorBinding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1), |
| }; |
| VkDescriptorSetLayoutBinding combined_bindings[] = { |
| CreateSingleDescriptorBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0), |
| }; |
| |
| VkDescriptorSetLayoutCreateInfo separate_set_layout_ci = LvlInitStruct<VkDescriptorSetLayoutCreateInfo>(); |
| separate_set_layout_ci.flags = 0; |
| separate_set_layout_ci.bindingCount = sizeof(separate_bindings) / sizeof(separate_bindings[0]); |
| separate_set_layout_ci.pBindings = separate_bindings; |
| |
| VkDescriptorSetLayoutCreateInfo combined_set_layout_ci = LvlInitStruct<VkDescriptorSetLayoutCreateInfo>(); |
| combined_set_layout_ci.flags = 0; |
| combined_set_layout_ci.bindingCount = sizeof(combined_bindings) / sizeof(combined_bindings[0]); |
| combined_set_layout_ci.pBindings = combined_bindings; |
| |
| vk_testing::DescriptorSetLayout separate_set_layout(*m_device, separate_set_layout_ci); |
| vk_testing::DescriptorSetLayout combined_set_layout(*m_device, combined_set_layout_ci); |
| |
| VkPipelineLayoutCreateInfo pipeline_layout_ci = LvlInitStruct<VkPipelineLayoutCreateInfo>(); |
| pipeline_layout_ci.flags = 0; |
| pipeline_layout_ci.pushConstantRangeCount = 0; |
| pipeline_layout_ci.pPushConstantRanges = nullptr; |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-CreatePipelineLayout-SeparateSampler"); |
| vk_testing::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci, {&separate_set_layout}); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-CreatePipelineLayout-SeparateSampler"); |
| vk_testing::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci, {&combined_set_layout}); |
| m_errorMonitor->Finish(); |
| } |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, CreatePipelineLayout_LargePipelineLayout) { |
| InitBestPracticesFramework(kEnableNVIDIAValidation); |
| InitState(); |
| |
| VkDescriptorSetLayoutBinding large_bindings[] = { |
| { 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 16, VK_SHADER_STAGE_VERTEX_BIT, nullptr }, |
| { 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr }, |
| }; |
| VkDescriptorSetLayoutBinding small_bindings[] = { |
| { 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 16, VK_SHADER_STAGE_VERTEX_BIT, nullptr }, |
| }; |
| |
| VkDescriptorSetLayoutCreateInfo large_set_layout_ci = LvlInitStruct<VkDescriptorSetLayoutCreateInfo>(); |
| large_set_layout_ci.flags = 0; |
| large_set_layout_ci.bindingCount = sizeof(large_bindings) / sizeof(large_bindings[0]); |
| large_set_layout_ci.pBindings = large_bindings; |
| |
| VkDescriptorSetLayoutCreateInfo small_set_layout_ci = LvlInitStruct<VkDescriptorSetLayoutCreateInfo>(); |
| small_set_layout_ci.flags = 0; |
| small_set_layout_ci.bindingCount = sizeof(small_bindings) / sizeof(small_bindings[0]); |
| small_set_layout_ci.pBindings = small_bindings; |
| |
| vk_testing::DescriptorSetLayout large_set_layout(*m_device, large_set_layout_ci); |
| vk_testing::DescriptorSetLayout small_set_layout(*m_device, small_set_layout_ci); |
| |
| VkPipelineLayoutCreateInfo pipeline_layout_ci = LvlInitStruct<VkPipelineLayoutCreateInfo>(); |
| pipeline_layout_ci.flags = 0; |
| pipeline_layout_ci.pushConstantRangeCount = 0; |
| pipeline_layout_ci.pPushConstantRanges = nullptr; |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-CreatePipelineLayout-LargePipelineLayout"); |
| vk_testing::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci, {&large_set_layout}); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-CreatePipelineLayout-LargePipelineLayout"); |
| vk_testing::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci, {&small_set_layout}); |
| m_errorMonitor->Finish(); |
| } |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, BindPipeline_SwitchTessGeometryMesh) |
| { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| |
| ASSERT_NO_FATAL_FAILURE(InitBestPracticesFramework(kEnableNVIDIAValidation)); |
| |
| if (DeviceValidationVersion() < VK_API_VERSION_1_1) { |
| GTEST_SKIP() << "At least Vulkan version 1.1 is required"; |
| } |
| |
| auto dynamic_rendering_features = LvlInitStruct<VkPhysicalDeviceDynamicRenderingFeaturesKHR>(); |
| auto features2 = GetPhysicalDeviceFeatures2(dynamic_rendering_features); |
| if (!dynamic_rendering_features.dynamicRendering) { |
| GTEST_SKIP() << "This test requires dynamicRendering"; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2)); |
| |
| char const *vsSource = R"glsl( |
| #version 450 |
| void main() {} |
| )glsl"; |
| |
| char const *gsSource = R"glsl( |
| #version 450 |
| layout(triangles) in; |
| layout(triangle_strip, max_vertices = 3) out; |
| void main() {} |
| )glsl"; |
| |
| VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj gs(this, gsSource, VK_SHADER_STAGE_GEOMETRY_BIT); |
| |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = LvlInitStruct<VkPipelineRenderingCreateInfo>(); |
| |
| CreatePipelineHelper vsPipe(*this); |
| vsPipe.InitInfo(); |
| vsPipe.shader_stages_ = {vs.GetStageCreateInfo()}; |
| vsPipe.InitState(); |
| vsPipe.gp_ci_.pNext = &pipeline_rendering_info; |
| vsPipe.CreateGraphicsPipeline(); |
| |
| CreatePipelineHelper vgsPipe(*this); |
| vgsPipe.InitInfo(); |
| vgsPipe.shader_stages_ = {vs.GetStageCreateInfo(), gs.GetStageCreateInfo()}; |
| vgsPipe.InitState(); |
| vgsPipe.gp_ci_.pNext = &pipeline_rendering_info; |
| vgsPipe.CreateGraphicsPipeline(); |
| |
| m_commandBuffer->begin(); |
| |
| { |
| m_errorMonitor->SetAllowedFailureMsg("UNASSIGNED-BestPractices-Pipeline-SortAndBind"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-BindPipeline-SwitchTessGeometryMesh"); |
| vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, vsPipe.pipeline_); |
| m_errorMonitor->Finish(); |
| } |
| { |
| m_errorMonitor->SetAllowedFailureMsg("UNASSIGNED-BestPractices-Pipeline-SortAndBind"); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-BindPipeline-SwitchTessGeometryMesh"); |
| for (int i = 0; i < 10; ++i) { |
| vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, vgsPipe.pipeline_); |
| vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, vsPipe.pipeline_); |
| } |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, BindPipeline_ZcullDirection) |
| { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| |
| ASSERT_NO_FATAL_FAILURE(InitBestPracticesFramework(kEnableNVIDIAValidation)); |
| |
| if (DeviceValidationVersion() < VK_API_VERSION_1_3) { |
| GTEST_SKIP() << "At least Vulkan version 1.3 is required"; |
| } |
| |
| VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamic_rendering_features = LvlInitStruct<VkPhysicalDeviceDynamicRenderingFeaturesKHR>(); |
| VkPhysicalDeviceSynchronization2Features synchronization2_features = LvlInitStruct<VkPhysicalDeviceSynchronization2Features>(&dynamic_rendering_features); |
| VkPhysicalDeviceFeatures2 features2 = GetPhysicalDeviceFeatures2(synchronization2_features); |
| if (!dynamic_rendering_features.dynamicRendering) { |
| GTEST_SKIP() << "This test requires dynamicRendering"; |
| } |
| if (!synchronization2_features.synchronization2) { |
| GTEST_SKIP() << "This test requires synchronization2"; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2)); |
| |
| VkFormat depth_format = VK_FORMAT_D32_SFLOAT_S8_UINT; |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = LvlInitStruct<VkPipelineRenderingCreateInfo>(); |
| pipeline_rendering_info.depthAttachmentFormat = depth_format; |
| pipeline_rendering_info.stencilAttachmentFormat = depth_format; |
| |
| VkImageObj image(m_device); |
| // 3 array layers |
| image.Init(image.ImageCreateInfo2D(32, 32, 1, 3, depth_format, |
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, |
| VK_IMAGE_TILING_OPTIMAL, 0)); |
| ASSERT_TRUE(image.initialized()); |
| |
| VkImageViewCreateInfo image_view_ci = LvlInitStruct<VkImageViewCreateInfo>(); |
| image_view_ci.image = image.handle(); |
| image_view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D; |
| image_view_ci.format = depth_format; |
| // rendering to layer index 1 |
| image_view_ci.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 1, 1}; |
| |
| vk_testing::ImageView depth_image_view(*m_device, image_view_ci); |
| |
| VkRenderingAttachmentInfo depth_attachment = LvlInitStruct<VkRenderingAttachmentInfo>(); |
| depth_attachment.imageLayout = VK_IMAGE_LAYOUT_GENERAL; |
| depth_attachment.imageView = depth_image_view.handle(); |
| depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; |
| |
| VkRenderingInfo begin_rendering_info = LvlInitStruct<VkRenderingInfo>(); |
| begin_rendering_info.renderArea.extent = {32, 32}; |
| begin_rendering_info.layerCount = 1; |
| begin_rendering_info.pDepthAttachment = &depth_attachment; |
| begin_rendering_info.pStencilAttachment = &depth_attachment; |
| |
| VkClearRect clear_rect{}; |
| clear_rect.baseArrayLayer = 0; |
| clear_rect.layerCount = 1; |
| clear_rect.rect.extent.width = 32; |
| clear_rect.rect.extent.height = 32; |
| |
| VkClearAttachment attachment{}; |
| attachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; |
| |
| VkImageMemoryBarrier discard_barrier = LvlInitStruct<VkImageMemoryBarrier>(); |
| discard_barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; |
| discard_barrier.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT; |
| discard_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| discard_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; |
| discard_barrier.image = image.handle(); |
| discard_barrier.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 1, |
| VK_REMAINING_ARRAY_LAYERS}; |
| |
| VkImageMemoryBarrier2 discard_barrier2 = LvlInitStruct<VkImageMemoryBarrier2>(); |
| discard_barrier2.srcAccessMask = VK_ACCESS_2_MEMORY_READ_BIT; |
| discard_barrier2.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT; |
| discard_barrier2.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| discard_barrier2.newLayout = VK_IMAGE_LAYOUT_GENERAL; |
| discard_barrier2.image = image.handle(); |
| discard_barrier2.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 1, |
| VK_REMAINING_ARRAY_LAYERS}; |
| |
| VkDependencyInfo discard_dependency_info = LvlInitStruct<VkDependencyInfo>(); |
| discard_dependency_info.imageMemoryBarrierCount = 1; |
| discard_dependency_info.pImageMemoryBarriers = &discard_barrier2; |
| |
| auto set_desired_failure_msg = [this] { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-Zcull-LessGreaterRatio"); |
| }; |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| void main() {} |
| )glsl"; |
| |
| VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| VkPipelineObj pipe(m_device); |
| pipe.AddShader(&vs); |
| pipe.AddDefaultColorAttachment(); |
| pipe.MakeDynamic(VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE); |
| pipe.MakeDynamic(VK_DYNAMIC_STATE_DEPTH_COMPARE_OP); |
| |
| VkPipelineDepthStencilStateCreateInfo depth_stencil_state_ci = LvlInitStruct<VkPipelineDepthStencilStateCreateInfo>(); |
| |
| VkPipelineLayoutCreateInfo pipeline_layout_ci = LvlInitStruct<VkPipelineLayoutCreateInfo>(); |
| vk_testing::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci); |
| |
| VkGraphicsPipelineCreateInfo create_info = LvlInitStruct<VkGraphicsPipelineCreateInfo>(); |
| pipe.InitGraphicsPipelineCreateInfo(&create_info); |
| create_info.pNext = &pipeline_rendering_info; |
| create_info.pDepthStencilState = &depth_stencil_state_ci; |
| pipe.CreateVKPipeline(pipeline_layout.handle(), VK_NULL_HANDLE, &create_info); |
| |
| VkViewport viewport = {}; |
| viewport.width = 32; |
| viewport.height = 32; |
| viewport.minDepth = 1.0f; |
| viewport.maxDepth = 1.0f; |
| |
| VkRect2D scissor = {}; |
| scissor.extent.width = 32; |
| scissor.extent.height = 32; |
| |
| VkCommandBufferBeginInfo begin_info = LvlInitStruct<VkCommandBufferBeginInfo>(); |
| m_commandBuffer->begin(&begin_info); |
| |
| auto cmd = m_commandBuffer->handle(); |
| |
| vk::CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle()); |
| vk::CmdSetDepthTestEnable(cmd, VK_TRUE); |
| |
| vk::CmdSetViewport(cmd, 0, 1, &viewport); |
| vk::CmdSetScissor(cmd, 0, 1, &scissor); |
| |
| { |
| SCOPED_TRACE("Unbalance"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 90; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 10; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| set_desired_failure_msg(); |
| vk::CmdEndRendering(cmd); |
| m_errorMonitor->Finish(); |
| } |
| |
| { |
| SCOPED_TRACE("Balance"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| set_desired_failure_msg(); |
| vk::CmdEndRendering(cmd); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| // This should miss because BeginRendering uses LOAD_OP_CLEAR |
| SCOPED_TRACE("Balance with end rendering"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdEndRendering(cmd); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| set_desired_failure_msg(); |
| vk::CmdEndRendering(cmd); |
| m_errorMonitor->Finish(); |
| } |
| |
| { |
| SCOPED_TRACE("Clear before balance"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdClearAttachments(cmd, 1, &attachment, 1, &clear_rect); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| set_desired_failure_msg(); |
| vk::CmdEndRendering(cmd); |
| m_errorMonitor->Finish(); |
| } |
| |
| { |
| SCOPED_TRACE("Balance before clear"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| set_desired_failure_msg(); |
| vk::CmdClearAttachments(cmd, 1, &attachment, 1, &clear_rect); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::CmdEndRendering(cmd); |
| } |
| |
| // The tests below use LOAD_OP for depth |
| depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; |
| |
| { |
| SCOPED_TRACE("Load previous scope"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdEndRendering(cmd); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| set_desired_failure_msg(); |
| vk::CmdEndRendering(cmd); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| SCOPED_TRACE("Transition to discard"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdEndRendering(cmd); |
| |
| vk::CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, |
| nullptr, 1, &discard_barrier); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| set_desired_failure_msg(); |
| vk::CmdEndRendering(cmd); |
| m_errorMonitor->Finish(); |
| } |
| |
| { |
| SCOPED_TRACE("Transition to discard 2"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdEndRendering(cmd); |
| |
| vk::CmdPipelineBarrier2(cmd, &discard_dependency_info); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| set_desired_failure_msg(); |
| vk::CmdEndRendering(cmd); |
| m_errorMonitor->Finish(); |
| } |
| |
| { |
| SCOPED_TRACE("Balance before discard"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdEndRendering(cmd); |
| |
| set_desired_failure_msg(); |
| vk::CmdPipelineBarrier2(cmd, &discard_dependency_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| { |
| SCOPED_TRACE("Transfer clear to discard"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdEndRendering(cmd); |
| |
| VkClearDepthStencilValue ds_value{}; |
| vk::CmdClearDepthStencilImage(cmd, image.handle(), VK_IMAGE_LAYOUT_GENERAL, &ds_value, 1, &discard_barrier.subresourceRange); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| set_desired_failure_msg(); |
| vk::CmdEndRendering(cmd); |
| m_errorMonitor->Finish(); |
| } |
| |
| { |
| SCOPED_TRACE("Transfer clear to validate"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdEndRendering(cmd); |
| |
| set_desired_failure_msg(); |
| VkClearDepthStencilValue ds_value{}; |
| vk::CmdClearDepthStencilImage(cmd, image.handle(), VK_IMAGE_LAYOUT_GENERAL, &ds_value, 1, &discard_barrier.subresourceRange); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| discard_barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; |
| |
| { |
| SCOPED_TRACE("Transfer clear with VK_REMAINING_ARRAY_LAYERS"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdEndRendering(cmd); |
| |
| VkClearDepthStencilValue ds_value{}; |
| vk::CmdClearDepthStencilImage(cmd, image.handle(), VK_IMAGE_LAYOUT_GENERAL, &ds_value, 1, |
| &discard_barrier.subresourceRange); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| set_desired_failure_msg(); |
| vk::CmdEndRendering(cmd); |
| m_errorMonitor->Finish(); |
| } |
| |
| discard_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; |
| |
| { |
| SCOPED_TRACE("Transfer clear with VK_REMAINING_MIP_LEVELS"); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_LESS); |
| for (int i = 0; i < 60; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| vk::CmdEndRendering(cmd); |
| |
| VkClearDepthStencilValue ds_value{}; |
| vk::CmdClearDepthStencilImage(cmd, image.handle(), VK_IMAGE_LAYOUT_GENERAL, &ds_value, 1, |
| &discard_barrier.subresourceRange); |
| |
| vk::CmdBeginRendering(cmd, &begin_rendering_info); |
| |
| vk::CmdSetDepthCompareOp(cmd, VK_COMPARE_OP_GREATER); |
| for (int i = 0; i < 40; ++i) m_commandBuffer->Draw(0, 0, 0, 0); |
| |
| set_desired_failure_msg(); |
| vk::CmdEndRendering(cmd); |
| m_errorMonitor->Finish(); |
| } |
| |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, ClearColor_NotCompressed) |
| { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| |
| ASSERT_NO_FATAL_FAILURE(InitBestPracticesFramework(kEnableNVIDIAValidation)); |
| |
| if (DeviceValidationVersion() < VK_API_VERSION_1_3) { |
| GTEST_SKIP() << "At least Vulkan version 1.3 is required"; |
| } |
| |
| VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamic_rendering_features = LvlInitStruct<VkPhysicalDeviceDynamicRenderingFeaturesKHR>(); |
| VkPhysicalDeviceFeatures2 features2 = GetPhysicalDeviceFeatures2(dynamic_rendering_features); |
| if (!dynamic_rendering_features.dynamicRendering) { |
| GTEST_SKIP() << "This test requires dynamicRendering"; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2)); |
| |
| auto set_desired = [this] { |
| m_errorMonitor->Finish(); |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, "UNASSIGNED-BestPractices-ClearColor-NotCompressed"); |
| m_errorMonitor->SetAllowedFailureMsg("UNASSIGNED-BestPractices-DrawState-ClearCmdBeforeDraw"); |
| }; |
| |
| VkImageObj image(m_device); |
| image.Init((uint32_t)m_width, (uint32_t)m_height, 1, VK_FORMAT_B8G8R8A8_UNORM, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); |
| ASSERT_TRUE(image.initialized()); |
| |
| VkImageViewCreateInfo image_view_ci = LvlInitStruct<VkImageViewCreateInfo>(); |
| image_view_ci.image = image.handle(); |
| image_view_ci.viewType = VK_IMAGE_VIEW_TYPE_2D; |
| image_view_ci.format = VK_FORMAT_B8G8R8A8_UNORM; |
| image_view_ci.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; |
| |
| vk_testing::ImageView image_view(*m_device, image_view_ci); |
| |
| VkRenderingAttachmentInfo color_attachment = LvlInitStruct<VkRenderingAttachmentInfo>(); |
| color_attachment.imageView = image_view.handle(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_GENERAL; |
| color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; |
| color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; |
| color_attachment.clearValue = {}; |
| |
| VkRenderingInfo begin_rendering_info = LvlInitStruct<VkRenderingInfo>(); |
| begin_rendering_info.renderArea.extent = {(uint32_t)m_width, (uint32_t)m_height}; |
| begin_rendering_info.layerCount = 1; |
| begin_rendering_info.colorAttachmentCount = 1; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| |
| VkClearAttachment clear{}; |
| clear.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| clear.clearValue.color.float32[0] = 0.0f; |
| clear.clearValue.color.float32[1] = 0.0f; |
| clear.clearValue.color.float32[2] = 0.0f; |
| clear.clearValue.color.float32[3] = 0.0f; |
| clear.colorAttachment = 0; |
| |
| auto set_clear_color = [&clear](const std::array<float, 4>& color) { |
| for (size_t i = 0; i < 4; ++i) { |
| clear.clearValue.color.float32[i] = color[i]; |
| } |
| }; |
| |
| VkClearRect clear_rect = {{{0, 0}, {(uint32_t)m_width, (uint32_t)m_height}}, 0, 1}; |
| |
| m_commandBuffer->begin(); |
| vk::CmdBeginRendering(m_commandBuffer->handle(), &begin_rendering_info); |
| |
| { |
| set_desired(); |
| set_clear_color({1.0f, 0.5f, 0.25f, 0.0f}); |
| |
| for (int i = 0; i < 16 + 1; ++i) { |
| clear.clearValue.color.float32[3] += 0.05f; |
| vk::CmdClearAttachments(m_commandBuffer->handle(), 1, &clear, 1, &clear_rect); |
| } |
| m_errorMonitor->VerifyFound(); |
| } |
| { |
| set_desired(); |
| set_clear_color({1.0f, 1.0f, 1.0f, 1.0f}); |
| vk::CmdClearAttachments(m_commandBuffer->handle(), 1, &clear, 1, &clear_rect); |
| m_errorMonitor->Finish(); |
| } |
| { |
| set_desired(); |
| set_clear_color({0.0f, 0.0f, 0.0f, 0.0f}); |
| vk::CmdClearAttachments(m_commandBuffer->handle(), 1, &clear, 1, &clear_rect); |
| m_errorMonitor->Finish(); |
| } |
| { |
| set_desired(); |
| set_clear_color({0.9f, 1.0f, 1.0f, 1.0f}); |
| vk::CmdClearAttachments(m_commandBuffer->handle(), 1, &clear, 1, &clear_rect); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| vk::CmdEndRendering(m_commandBuffer->handle()); |
| |
| { |
| set_desired(); |
| vk::CmdBeginRendering(m_commandBuffer->handle(), &begin_rendering_info); |
| m_errorMonitor->Finish(); |
| vk::CmdEndRendering(m_commandBuffer->handle()); |
| } |
| { |
| color_attachment.clearValue.color.float32[0] = 0.55f; |
| |
| set_desired(); |
| vk::CmdBeginRendering(m_commandBuffer->handle(), &begin_rendering_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(VkNvidiaBestPracticesLayerTest, BeginCommandBuffer_OneTimeSubmit) { |
| InitBestPracticesFramework(kEnableNVIDIAValidation); |
| InitState(); |
| |
| VkResult err = VK_SUCCESS; |
| |
| VkCommandPoolCreateInfo command_pool_ci = LvlInitStruct<VkCommandPoolCreateInfo>(); |
| command_pool_ci.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; |
| command_pool_ci.queueFamilyIndex = m_device->graphics_queue_node_index_; |
| |
| vk_testing::CommandPool command_pool(*m_device, command_pool_ci); |
| |
| VkCommandBufferAllocateInfo allocate_info = LvlInitStruct<VkCommandBufferAllocateInfo>(); |
| allocate_info.commandPool = command_pool.handle(); |
| allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
| allocate_info.commandBufferCount = 1; |
| vk_testing::CommandBuffer command_buffer0(*m_device, allocate_info); |
| vk_testing::CommandBuffer command_buffer1(*m_device, allocate_info); |
| vk_testing::CommandBuffer command_buffer2(*m_device, allocate_info); |
| |
| VkSubmitInfo submit_info = LvlInitStruct<VkSubmitInfo>(); |
| submit_info.commandBufferCount = 1; |
| |
| VkCommandBufferBeginInfo begin_info = LvlInitStruct<VkCommandBufferBeginInfo>(); |
| |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-vkBeginCommandBuffer-one-time-submit"); |
| |
| submit_info.pCommandBuffers = &command_buffer0.handle(); |
| |
| command_buffer0.begin(&begin_info); |
| command_buffer0.end(); |
| |
| err = vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| ASSERT_VK_SUCCESS(err); |
| |
| m_device->wait(); |
| |
| err = vk::BeginCommandBuffer(command_buffer0.handle(), &begin_info); |
| m_errorMonitor->VerifyFound(); |
| |
| if (err == VK_SUCCESS) { |
| command_buffer0.end(); |
| } |
| } |
| { |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-vkBeginCommandBuffer-one-time-submit"); |
| |
| submit_info.pCommandBuffers = &command_buffer1.handle(); |
| |
| command_buffer1.begin(&begin_info); |
| command_buffer1.end(); |
| |
| for (int i = 0; i < 2; ++i) { |
| err = vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| ASSERT_VK_SUCCESS(err); |
| |
| m_device->wait(); |
| } |
| |
| err = vk::BeginCommandBuffer(command_buffer1.handle(), &begin_info); |
| m_errorMonitor->Finish(); |
| |
| if (err == VK_SUCCESS) { |
| command_buffer1.end(); |
| } |
| } |
| { |
| begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
| m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, |
| "UNASSIGNED-BestPractices-vkBeginCommandBuffer-one-time-submit"); |
| |
| submit_info.pCommandBuffers = &command_buffer2.handle(); |
| |
| command_buffer2.begin(&begin_info); |
| command_buffer2.end(); |
| |
| err = vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); |
| ASSERT_VK_SUCCESS(err); |
| |
| m_device->wait(); |
| |
| err = vk::BeginCommandBuffer(command_buffer2.handle(), &begin_info); |
| m_errorMonitor->Finish(); |
| |
| if (err == VK_SUCCESS) { |
| command_buffer2.end(); |
| } |
| } |
| } |