| /* |
| * Copyright (c) 2015-2025 The Khronos Group Inc. |
| * Copyright (c) 2015-2025 Valve Corporation |
| * Copyright (c) 2015-2025 LunarG, Inc. |
| * Modifications Copyright (C) 2020-2022 Advanced Micro Devices, Inc. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| */ |
| |
| #include <vulkan/vulkan_core.h> |
| #include "../framework/layer_validation_tests.h" |
| #include "../framework/pipeline_helper.h" |
| |
| // Tests for AMD-specific best practices |
| const char *kEnableAMDValidation = "validate_best_practices_amd"; |
| |
| class VkAmdBestPracticesLayerTest : public VkBestPracticesLayerTest {}; |
| |
| // this is a very long test (~10 minutes) |
| // disabled for now |
| #ifdef AMD_LONG_RUNNING_TEST |
| TEST_F(VkAmdBestPracticesLayerTest, TooManyPipelines) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| InitRenderTarget(); |
| |
| // create 1 more than the warning limit for pipeline objects |
| const uint32_t warn_limit = 5001; |
| VkPipeline pipeline_Array[warn_limit + 1] = {}; |
| |
| for (int i = 0; i <= warn_limit; i++) { |
| // create a new pipeline helper so the cache won't be used |
| // also imitates a "just in time" pipeline creator pattern |
| if (i == 1) { |
| // check that the second pipeline helper cache was detected |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, |
| "BestPractices-vkCreatePipelines-multiple-pipelines-caches"); |
| } |
| CreatePipelineHelper pipe(*this); |
| pipe.CreateGraphicsPipeline(); |
| pipeline_Array[i] = pipe; |
| if (i == 1) { |
| // change check to too many pipelines |
| m_errorMonitor->VerifyFound(); |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-CreatePipelines-TooManyPipelines"); |
| } |
| } |
| |
| m_errorMonitor->VerifyFound(); |
| } |
| #endif |
| |
| TEST_F(VkAmdBestPracticesLayerTest, UseMutableRT) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| // create a colot attachment image with mutable bit set |
| auto image_ci = vkt::Image::ImageCreateInfo2D(1, 1, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| image_ci.imageType = VK_IMAGE_TYPE_1D; |
| image_ci.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; |
| |
| VkImage test_image = VK_NULL_HANDLE; |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-vkImage-DontUseMutableRenderTargets"); |
| vk::CreateImage(*m_device, &image_ci, nullptr, &test_image); |
| m_errorMonitor->VerifyFound(); |
| |
| // create a depth attachment image with mutable bit set |
| image_ci.format = VK_FORMAT_D32_SFLOAT; |
| image_ci.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; |
| if (IsImageFormatSupported(Gpu(), image_ci, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-vkImage-DontUseMutableRenderTargets"); |
| vk::CreateImage(*m_device, &image_ci, nullptr, &test_image); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // create a storage image with mutable bit set |
| image_ci.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_ci.usage = VK_IMAGE_USAGE_STORAGE_BIT; |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-vkImage-DontUseMutableRenderTargets"); |
| vk::CreateImage(*m_device, &image_ci, nullptr, &test_image); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, UsageConcurentRT) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| if (m_device->Physical().queue_properties_.size() < 2) { |
| GTEST_SKIP() << "Test not supported by a single queue family device"; |
| } |
| |
| std::vector<uint32_t> queueFamilies(m_device->Physical().queue_properties_.size()); |
| for (size_t i = 0; i < m_device->Physical().queue_properties_.size(); i++) { |
| queueFamilies[i] = i; |
| } |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(1, 1, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| image_ci.sharingMode = VK_SHARING_MODE_CONCURRENT; |
| image_ci.queueFamilyIndexCount = (uint32_t)queueFamilies.size(); |
| image_ci.pQueueFamilyIndices = queueFamilies.data(); |
| VkImage test_image = VK_NULL_HANDLE; |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-vkImage-AvoidConcurrentRenderTargets"); |
| vk::CreateImage(*m_device, &image_ci, nullptr, &test_image); |
| m_errorMonitor->VerifyFound(); |
| |
| image_ci.format = VK_FORMAT_D32_SFLOAT; |
| image_ci.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; |
| if (IsImageFormatSupported(Gpu(), image_ci, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-vkImage-AvoidConcurrentRenderTargets"); |
| vk::CreateImage(*m_device, &image_ci, nullptr, &test_image); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, UsageStorageRT) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(1, 1, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT); |
| VkImage test_image = VK_NULL_HANDLE; |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-vkImage-DontUseStorageRenderTargets"); |
| vk::CreateImage(*m_device, &image_ci, nullptr, &test_image); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, PrimitiveRestart) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-CreatePipelines-AvoidPrimitiveRestart"); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.ia_ci_.primitiveRestartEnable = true; |
| pipe.CreateGraphicsPipeline(); |
| |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, NumDynamicStates) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| // fill the dynamic array with the first 8 types in the enum |
| // imitates a case where the user have set most dynamic states unnecessarily |
| VkDynamicState dynamic_states_array[8] = {}; |
| for (uint32_t i = 0; i < 8; i++) { |
| dynamic_states_array[i] = (VkDynamicState)i; |
| } |
| |
| VkPipelineDynamicStateCreateInfo dynamic_state_info = vku::InitStructHelper(); |
| dynamic_state_info.dynamicStateCount = 8; |
| dynamic_state_info.pDynamicStates = dynamic_states_array; |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.dyn_state_ci_ = dynamic_state_info; |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-CreatePipelines-MinimizeNumDynamicStates"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, KeepLayoutSmall) { |
| // TODO: add dynamic buffer check as well |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| // create a layout of 15 DWORDS (40 bytes push constants (10 DWORDS), a descriptor set (1 DWORD), and 2 dynamic buffers (4 |
| // DWORDS) |
| uint32_t push_size_dwords = 10; |
| VkPushConstantRange push_range = {VK_SHADER_STAGE_ALL, 0, 4 * push_size_dwords}; |
| |
| vkt::DescriptorSetLayout ds_layout(*m_device, |
| {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 2, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}); |
| |
| VkPipelineLayoutCreateInfo pipeline_layout_info = vku::InitStructHelper(); |
| pipeline_layout_info.setLayoutCount = 1; |
| pipeline_layout_info.pSetLayouts = &ds_layout.handle(); |
| pipeline_layout_info.pushConstantRangeCount = 1; |
| pipeline_layout_info.pPushConstantRanges = &push_range; |
| |
| VkPipelineLayout test_pipeline_layout = VK_NULL_HANDLE; |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-CreatePipelinesLayout-KeepLayoutSmall"); |
| vk::CreatePipelineLayout(*m_device, &pipeline_layout_info, nullptr, &test_pipeline_layout); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, CopyingDescriptors) { |
| // TODO: add dynamic buffer check as well |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| VkDescriptorPoolSize ds_type_count = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 2}; |
| VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(); |
| ds_pool_ci.maxSets = 2; |
| ds_pool_ci.poolSizeCount = 1; |
| ds_pool_ci.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; |
| ds_pool_ci.pPoolSizes = &ds_type_count; |
| |
| vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci); |
| const vkt::DescriptorSetLayout ds_layout( |
| *m_device, {2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}); |
| |
| VkDescriptorSet descriptor_sets[2] = {}; |
| VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper(); |
| alloc_info.descriptorSetCount = 1; |
| alloc_info.descriptorPool = ds_pool; |
| alloc_info.pSetLayouts = &ds_layout.handle(); |
| vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_sets[0]); |
| vk::AllocateDescriptorSets(device(), &alloc_info, &descriptor_sets[1]); |
| |
| VkCopyDescriptorSet copy_info = vku::InitStructHelper(); |
| copy_info.descriptorCount = 1; |
| copy_info.srcSet = descriptor_sets[1]; |
| copy_info.srcBinding = 2; |
| copy_info.srcArrayElement = 0; |
| copy_info.dstSet = descriptor_sets[0]; |
| copy_info.dstBinding = 2; |
| copy_info.dstArrayElement = 0; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-UpdateDescriptors-AvoidCopyingDescriptors"); |
| vk::UpdateDescriptorSets(*m_device, 0, nullptr, 1, ©_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, ClearImage) { |
| TEST_DESCRIPTION("Test for validating usage of vkCmdClearAttachments"); |
| |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| { |
| auto image_ci = vkt::Image::ImageCreateInfo2D(1, 1, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); |
| image_ci.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; |
| vkt::Image image(*m_device, image_ci); |
| |
| m_command_buffer.Begin(); |
| image.SetLayout(m_command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); |
| |
| VkClearColorValue clear_value = {{0.0f, 0.0f, 0.0f, 0.0f}}; |
| VkImageSubresourceRange image_range = {}; |
| image_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| image_range.levelCount = 1; |
| image_range.layerCount = 1; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-ClearAttachment-ClearImage-color"); |
| vk::CmdClearColorImage(m_command_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_value, 1, &image_range); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| vk::ResetCommandPool(device(), m_command_pool, 0); |
| |
| { |
| auto image_ci = |
| vkt::Image::ImageCreateInfo2D(1, 1, 1, 1, VK_FORMAT_D32_SFLOAT_S8_UINT, |
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); |
| image_ci.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; |
| if (IsImageFormatSupported(Gpu(), image_ci, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { |
| vkt::Image image(*m_device, image_ci); |
| |
| m_command_buffer.Begin(); |
| image.SetLayout(m_command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); |
| |
| VkClearDepthStencilValue clear_value = {0.0f, 0}; |
| VkImageSubresourceRange image_range = {}; |
| image_range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; |
| image_range.levelCount = 1; |
| image_range.layerCount = 1; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, |
| "BestPractices-AMD-ClearAttachment-ClearImage-depth-stencil"); |
| vk::CmdClearDepthStencilImage(m_command_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_value, 1, |
| &image_range); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| } |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, ImageToImageCopy) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(1, 1, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); |
| vkt::Image image_1(*m_device, image_ci); |
| |
| image_ci.tiling = VK_IMAGE_TILING_LINEAR; |
| image_ci.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
| vkt::Image image_2(*m_device, image_ci, vkt::set_layout); |
| if (!image_2.initialized()) { |
| GTEST_SKIP() << "Could not initilize Linear image, skipping image to image copy test"; |
| } |
| |
| m_command_buffer.Begin(); |
| |
| image_1.SetLayout(m_command_buffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); |
| |
| VkImageCopy copy{}; |
| copy.extent = image_ci.extent; |
| copy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| copy.dstSubresource.layerCount = 1; |
| copy.srcSubresource = copy.dstSubresource; |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-vkImage-AvoidImageToImageCopy"); |
| vk::CmdCopyImage(m_command_buffer, image_1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image_2, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| 1, ©); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, GeneralLayout) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| // the init function initializes to general layout |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-vkImage-AvoidGeneral"); |
| auto image_ci = vkt::Image::ImageCreateInfo2D(1024, 1024, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| vkt::Image image(*m_device, image_ci); |
| image.SetLayout(VK_IMAGE_LAYOUT_GENERAL); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, RobustAccessOn) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| VkPhysicalDeviceFeatures features = {}; |
| features.robustBufferAccess = true; |
| |
| const float q_priority[] = {1.0f}; |
| VkDeviceQueueCreateInfo queue_ci = vku::InitStructHelper(); |
| queue_ci.queueFamilyIndex = 0; |
| queue_ci.queueCount = 1; |
| queue_ci.pQueuePriorities = q_priority; |
| |
| VkDeviceCreateInfo device_ci = vku::InitStructHelper(); |
| device_ci.queueCreateInfoCount = 1; |
| device_ci.pQueueCreateInfos = &queue_ci; |
| device_ci.pEnabledFeatures = &features; |
| |
| VkDevice test_device; |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-vkCreateDevice-RobustBufferAccess"); |
| vk::CreateDevice(Gpu(), &device_ci, nullptr, &test_device); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, Barriers) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D( |
| 256, 256, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); |
| image_ci.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; |
| vkt::Image image(*m_device, image_ci); |
| |
| m_command_buffer.Begin(); |
| // check for read-to-read barrier |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-PipelineBarrier-readToReadBarrier"); |
| image.SetLayout(m_command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| image.TransitionLayout(m_command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); |
| |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetUnexpectedError("VUID-VkImageMemoryBarrier-oldLayout-01197"); |
| |
| // check total number of barriers warning |
| uint32_t warn_limit = 250; |
| for (uint32_t i = 0; i < warn_limit; i++) { |
| image.TransitionLayout(m_command_buffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
| image.TransitionLayout(m_command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); |
| } |
| |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-CmdBuffer-highBarrierCount"); |
| image.TransitionLayout(m_command_buffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, NumberOfSubmissions) { |
| AddSurfaceExtension(); |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| RETURN_IF_SKIP(InitSwapchain()); |
| InitRenderTarget(); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(256, 256, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| image_ci.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; |
| vkt::Image image(*m_device, image_ci); |
| image.SetLayout(VK_IMAGE_LAYOUT_GENERAL); |
| |
| uint32_t warn_limit = 11; |
| |
| for (uint32_t i = 0; i < warn_limit; i++) { |
| image.TransitionLayout(VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
| image.TransitionLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); |
| } |
| |
| vkt::Semaphore image_acquired(*m_device); |
| const uint32_t current_buffer = m_swapchain.AcquireNextImage(image_acquired, kWaitTimeout); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-Submission-ReduceNumberOfSubmissions"); |
| m_errorMonitor->SetUnexpectedError("VUID-VkPresentInfoKHR-pImageIndices-01430"); |
| m_default_queue->Present(m_swapchain, current_buffer, image_acquired); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, NumSyncPrimitives) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| constexpr int fence_warn_limit = 5; |
| std::vector<vkt::Fence> test_fences; |
| for (int i = 0; i < fence_warn_limit - 1; ++i) { |
| test_fences.emplace_back(*m_device); |
| } |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-SyncObjects-HighNumberOfFences"); |
| test_fences.emplace_back(*m_device); |
| m_errorMonitor->VerifyFound(); |
| |
| constexpr int semaphore_warn_limit = 12; |
| const VkSemaphoreCreateInfo semaphore_ci = vku::InitStructHelper(); |
| std::vector<vkt::Semaphore> test_semaphores(semaphore_warn_limit); |
| for (int i = 0; i < semaphore_warn_limit - 1; ++i) { |
| test_semaphores[i].Init(*m_device, semaphore_ci); |
| } |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-SyncObjects-HighNumberOfSemaphores"); |
| test_semaphores[semaphore_warn_limit - 1].Init(*m_device, semaphore_ci); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, SecondaryCmdBuffer) { |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| InitRenderTarget(); |
| |
| VkPipelineMultisampleStateCreateInfo pipe_ms_state_ci = vku::InitStructHelper(); |
| pipe_ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; |
| pipe_ms_state_ci.sampleShadingEnable = 0; |
| pipe_ms_state_ci.minSampleShading = 1.0; |
| pipe_ms_state_ci.pSampleMask = NULL; |
| |
| vkt::Buffer vertex_buffer(*m_device, 64, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.ms_ci_ = pipe_ms_state_ci; |
| pipe.CreateGraphicsPipeline(); |
| |
| vkt::CommandPool pool(*m_device, m_device->graphics_queue_node_index_); |
| vkt::CommandBuffer secondary_cmd_buf(*m_device, pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY); |
| |
| VkCommandBufferInheritanceInfo iinfo = vku::InitStructHelper(); |
| iinfo.renderPass = m_renderPassBeginInfo.renderPass; |
| |
| VkCommandBufferBeginInfo binfo = vku::InitStructHelper(); |
| binfo.pInheritanceInfo = &iinfo; |
| binfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; |
| // record a secondary command buffer |
| secondary_cmd_buf.Begin(&binfo); |
| |
| vk::CmdBindPipeline(secondary_cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| VkDeviceSize offset = 0; |
| vk::CmdBindVertexBuffers(secondary_cmd_buf, 0, 1, &vertex_buffer.handle(), &offset); |
| vk::CmdDraw(secondary_cmd_buf, 1, 0, 0, 0); |
| vk::CmdDraw(secondary_cmd_buf, 1, 0, 0, 0); |
| vk::CmdDraw(secondary_cmd_buf, 1, 0, 0, 0); |
| vk::CmdDraw(secondary_cmd_buf, 1, 0, 0, 0); |
| |
| VkClearAttachment color_attachment; |
| color_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| color_attachment.clearValue.color.float32[0] = 1.0; |
| color_attachment.clearValue.color.float32[1] = 1.0; |
| color_attachment.clearValue.color.float32[2] = 1.0; |
| color_attachment.clearValue.color.float32[3] = 1.0; |
| color_attachment.colorAttachment = 0; |
| VkClearRect clear_rect = {{{0, 0}, {m_width, m_height}}, 0, 1}; |
| |
| vk::CmdClearAttachments(secondary_cmd_buf, 1, &color_attachment, 1, &clear_rect); |
| |
| secondary_cmd_buf.End(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-VkCommandBuffer-AvoidSecondaryCmdBuffers"); |
| |
| vk::CmdExecuteCommands(m_command_buffer, 1, &secondary_cmd_buf.handle()); |
| |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, ComputeWorkgroupSize) { |
| TEST_DESCRIPTION("On AMD make the workgroup size a multiple of 64 to obtain best performance across all GPU generations."); |
| |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| // workgroup size = 4 |
| { |
| VkShaderObj compute_4_1_1(*m_device, |
| "#version 320 es\n" |
| "\n" |
| "layout(local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n\n" |
| "void main() {}\n", |
| VK_SHADER_STAGE_COMPUTE_BIT); |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-LocalWorkgroup-Multiple64"); |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cp_ci_.stage = compute_4_1_1.GetStageCreateInfo(); |
| pipe.CreateComputePipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // workgroup size = 64 |
| { |
| VkShaderObj compute_8_8_1(*m_device, |
| "#version 320 es\n" |
| "\n" |
| "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;\n\n" |
| "void main() {}\n", |
| VK_SHADER_STAGE_COMPUTE_BIT); |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cp_ci_.stage = compute_8_8_1.GetStageCreateInfo(); |
| pipe.CreateComputePipeline(); |
| } |
| |
| // workgroup size = 128 |
| { |
| VkShaderObj compute_16_8_1(*m_device, |
| "#version 320 es\n" |
| "\n" |
| "layout(local_size_x = 16, local_size_y = 8, local_size_z = 1) in;\n\n" |
| "void main() {}\n", |
| VK_SHADER_STAGE_COMPUTE_BIT); |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cp_ci_.stage = compute_16_8_1.GetStageCreateInfo(); |
| pipe.CreateComputePipeline(); |
| } |
| } |
| |
| TEST_F(VkAmdBestPracticesLayerTest, ComputeWorkgroupSizeMaintenance5) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance5); |
| RETURN_IF_SKIP(InitBestPracticesFramework(kEnableAMDValidation)); |
| RETURN_IF_SKIP(InitState()); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout(local_size_x = 4, local_size_y = 1, local_size_z = 1) in; |
| void main(){} |
| )glsl"; |
| |
| std::vector<uint32_t> shader = GLSLToSPV(VK_SHADER_STAGE_COMPUTE_BIT, cs_source); |
| |
| VkShaderModuleCreateInfo module_create_info = vku::InitStructHelper(); |
| module_create_info.pCode = shader.data(); |
| module_create_info.codeSize = shader.size() * sizeof(uint32_t); |
| |
| VkPipelineShaderStageCreateInfo stage_ci = vku::InitStructHelper(&module_create_info); |
| stage_ci.stage = VK_SHADER_STAGE_COMPUTE_BIT; |
| stage_ci.module = VK_NULL_HANDLE; |
| stage_ci.pName = "main"; |
| |
| vkt::PipelineLayout layout(*m_device, {}); |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cp_ci_.stage = stage_ci; |
| pipe.cp_ci_.layout = layout; |
| m_errorMonitor->SetDesiredFailureMsg(kPerformanceWarningBit, "BestPractices-AMD-LocalWorkgroup-Multiple64"); |
| pipe.CreateComputePipeline(false); |
| m_errorMonitor->VerifyFound(); |
| } |