blob: d3cf6555a5f7041b4a270a85562b0728dd7ca489 [file] [log] [blame]
/*
* 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, &copy_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, &copy);
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();
}