// Copyright 2018 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // VulkanCommandBufferPerf: // Performance benchmark for Vulkan Primary/Secondary Command Buffer implementations. // Can run just these tests by adding "--gtest_filter=VulkanCommandBufferPerfTest*" // option to angle_white_box_perftests. // When running on Android with run_angle_white_box_perftests, use "-v" option. #include "ANGLEPerfTest.h" #include "common/platform.h" #include "test_utils/third_party/vulkan_command_buffer_utils.h" #if defined(ANDROID) # define NUM_CMD_BUFFERS 1000 // Android devices tend to be slower so only do 10 frames to avoid timeout # define NUM_FRAMES 10 #else # define NUM_CMD_BUFFERS 1000 # define NUM_FRAMES 100 #endif // These are minimal shaders used to submit trivial draw commands to command // buffers so that we can create large batches of cmd buffers with consistent // draw patterns but size/type of cmd buffers can be varied to test cmd buffer // differences across devices. constexpr char kVertShaderText[] = R"( #version 400 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable layout (std140, binding = 0) uniform bufferVals { mat4 mvp; } myBufferVals; layout (location = 0) in vec4 pos; layout (location = 1) in vec4 inColor; layout (location = 0) out vec4 outColor; void main() { outColor = inColor; gl_Position = myBufferVals.mvp * pos; })"; constexpr char kFragShaderText[] = R"( #version 400 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable layout (location = 0) in vec4 color; layout (location = 0) out vec4 outColor; void main() { outColor = color; })"; using CommandBufferImpl = void (*)(sample_info &info, VkClearValue *clear_values, VkFence drawFence, VkSemaphore imageAcquiredSemaphore, int numBuffers); struct CommandBufferTestParams { CommandBufferImpl CBImplementation; std::string story; int frames = NUM_FRAMES; int buffers = NUM_CMD_BUFFERS; }; class VulkanCommandBufferPerfTest : public ANGLEPerfTest, public ::testing::WithParamInterface { public: VulkanCommandBufferPerfTest(); void SetUp() override; void TearDown() override; void step() override; private: VkClearValue mClearValues[2] = {}; VkSemaphore mImageAcquiredSemaphore = VK_NULL_HANDLE; VkFence mDrawFence = VK_NULL_HANDLE; VkResult res = VK_NOT_READY; const bool mDepthPresent = true; struct sample_info mInfo = {}; std::string mSampleTitle; CommandBufferImpl mCBImplementation = nullptr; int mFrames = 0; int mBuffers = 0; }; VulkanCommandBufferPerfTest::VulkanCommandBufferPerfTest() : ANGLEPerfTest("VulkanCommandBufferPerfTest", "", GetParam().story, GetParam().frames) { mInfo = {}; mSampleTitle = "Draw Textured Cube"; mCBImplementation = GetParam().CBImplementation; mFrames = GetParam().frames; mBuffers = GetParam().buffers; // This test appears to be flaky on multiple platforms. #if !defined(ANGLE_PLATFORM_ANDROID) // mSkipTest = true; #endif // !defined(ANGLE_PLATFORM_ANDROID) } void VulkanCommandBufferPerfTest::SetUp() { if (mSkipTest) { return; } init_global_layer_properties(mInfo); init_instance_extension_names(mInfo); init_device_extension_names(mInfo); init_instance(mInfo, mSampleTitle.c_str()); init_enumerate_device(mInfo); init_window_size(mInfo, 500, 500); init_connection(mInfo); init_window(mInfo); init_swapchain_extension(mInfo); init_device(mInfo); init_command_pool(mInfo, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); init_command_buffer(mInfo); // Primary command buffer to hold secondaries init_command_buffer_array(mInfo, mBuffers); // Array of primary command buffers init_command_buffer2_array(mInfo, mBuffers); // Array containing all secondary buffers init_device_queue(mInfo); init_swap_chain(mInfo); init_depth_buffer(mInfo); init_uniform_buffer(mInfo); init_descriptor_and_pipeline_layouts(mInfo, false); init_renderpass(mInfo, mDepthPresent); init_shaders(mInfo, kVertShaderText, kFragShaderText); init_framebuffers(mInfo, mDepthPresent); init_vertex_buffer(mInfo, g_vb_solid_face_colors_Data, sizeof(g_vb_solid_face_colors_Data), sizeof(g_vb_solid_face_colors_Data[0]), false); init_descriptor_pool(mInfo, false); init_descriptor_set(mInfo); init_pipeline_cache(mInfo); init_pipeline(mInfo, mDepthPresent); mClearValues[0].color.float32[0] = 0.2f; mClearValues[0].color.float32[1] = 0.2f; mClearValues[0].color.float32[2] = 0.2f; mClearValues[0].color.float32[3] = 0.2f; mClearValues[1].depthStencil.depth = 1.0f; mClearValues[1].depthStencil.stencil = 0; VkSemaphoreCreateInfo imageAcquiredSemaphoreCreateInfo; imageAcquiredSemaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; imageAcquiredSemaphoreCreateInfo.pNext = NULL; imageAcquiredSemaphoreCreateInfo.flags = 0; res = vkCreateSemaphore(mInfo.device, &imageAcquiredSemaphoreCreateInfo, NULL, &mImageAcquiredSemaphore); ASSERT_EQ(VK_SUCCESS, res); VkFenceCreateInfo fenceInfo; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.pNext = NULL; fenceInfo.flags = 0; res = vkCreateFence(mInfo.device, &fenceInfo, NULL, &mDrawFence); ASSERT_EQ(VK_SUCCESS, res); } void VulkanCommandBufferPerfTest::step() { for (int x = 0; x < mFrames; x++) { mInfo.current_buffer = x % mInfo.swapchainImageCount; // Get the index of the next available swapchain image: res = vkAcquireNextImageKHR(mInfo.device, mInfo.swap_chain, UINT64_MAX, mImageAcquiredSemaphore, VK_NULL_HANDLE, &mInfo.current_buffer); // Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR // return codes ASSERT_EQ(VK_SUCCESS, res); mCBImplementation(mInfo, mClearValues, mDrawFence, mImageAcquiredSemaphore, mBuffers); } } void VulkanCommandBufferPerfTest::TearDown() { if (mSkipTest) { return; } vkDestroySemaphore(mInfo.device, mImageAcquiredSemaphore, NULL); vkDestroyFence(mInfo.device, mDrawFence, NULL); destroy_pipeline(mInfo); destroy_pipeline_cache(mInfo); destroy_descriptor_pool(mInfo); destroy_vertex_buffer(mInfo); destroy_framebuffers(mInfo); destroy_shaders(mInfo); destroy_renderpass(mInfo); destroy_descriptor_and_pipeline_layouts(mInfo); destroy_uniform_buffer(mInfo); destroy_depth_buffer(mInfo); destroy_swap_chain(mInfo); destroy_command_buffer2_array(mInfo, mBuffers); destroy_command_buffer_array(mInfo, mBuffers); destroy_command_buffer(mInfo); destroy_command_pool(mInfo); destroy_device(mInfo); destroy_window(mInfo); destroy_instance(mInfo); ANGLEPerfTest::TearDown(); } // Common code to present image used by all tests void Present(sample_info &info, VkFence drawFence) { // Now present the image in the window VkPresentInfoKHR present; present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present.pNext = NULL; present.swapchainCount = 1; present.pSwapchains = &info.swap_chain; present.pImageIndices = &info.current_buffer; present.pWaitSemaphores = NULL; present.waitSemaphoreCount = 0; present.pResults = NULL; // Make sure command buffer is finished before presenting VkResult res; do { res = vkWaitForFences(info.device, 1, &drawFence, VK_TRUE, FENCE_TIMEOUT); } while (res == VK_TIMEOUT); vkResetFences(info.device, 1, &drawFence); ASSERT_EQ(VK_SUCCESS, res); res = vkQueuePresentKHR(info.present_queue, &present); ASSERT_EQ(VK_SUCCESS, res); } // 100 separate primary cmd buffers, each with 1 Draw void PrimaryCommandBufferBenchmarkHundredIndividual(sample_info &info, VkClearValue *clear_values, VkFence drawFence, VkSemaphore imageAcquiredSemaphore, int numBuffers) { VkResult res; VkRenderPassBeginInfo rpBegin; rpBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rpBegin.pNext = NULL; rpBegin.renderPass = info.render_pass; rpBegin.framebuffer = info.framebuffers[info.current_buffer]; rpBegin.renderArea.offset.x = 0; rpBegin.renderArea.offset.y = 0; rpBegin.renderArea.extent.width = info.width; rpBegin.renderArea.extent.height = info.height; rpBegin.clearValueCount = 2; rpBegin.pClearValues = clear_values; VkCommandBufferBeginInfo cmdBufferInfo = {}; cmdBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; cmdBufferInfo.pNext = NULL; cmdBufferInfo.flags = 0; cmdBufferInfo.pInheritanceInfo = NULL; for (int x = 0; x < numBuffers; x++) { vkBeginCommandBuffer(info.cmds[x], &cmdBufferInfo); vkCmdBeginRenderPass(info.cmds[x], &rpBegin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(info.cmds[x], VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline); vkCmdBindDescriptorSets(info.cmds[x], VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, info.desc_set.data(), 0, NULL); const VkDeviceSize offsets[1] = {0}; vkCmdBindVertexBuffers(info.cmds[x], 0, 1, &info.vertex_buffer.buf, offsets); init_viewports_array(info, x); init_scissors_array(info, x); vkCmdDraw(info.cmds[x], 0, 1, 0, 0); vkCmdEndRenderPass(info.cmds[x]); res = vkEndCommandBuffer(info.cmds[x]); ASSERT_EQ(VK_SUCCESS, res); } VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submitInfo[1] = {}; submitInfo[0].pNext = NULL; submitInfo[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo[0].waitSemaphoreCount = 1; submitInfo[0].pWaitSemaphores = &imageAcquiredSemaphore; submitInfo[0].pWaitDstStageMask = &pipe_stage_flags; submitInfo[0].commandBufferCount = numBuffers; submitInfo[0].pCommandBuffers = info.cmds.data(); submitInfo[0].signalSemaphoreCount = 0; submitInfo[0].pSignalSemaphores = NULL; // Queue the command buffer for execution res = vkQueueSubmit(info.graphics_queue, 1, submitInfo, drawFence); ASSERT_EQ(VK_SUCCESS, res); Present(info, drawFence); } // 100 of the same Draw cmds in the same primary cmd buffer void PrimaryCommandBufferBenchmarkOneWithOneHundred(sample_info &info, VkClearValue *clear_values, VkFence drawFence, VkSemaphore imageAcquiredSemaphore, int numBuffers) { VkResult res; VkRenderPassBeginInfo rpBegin; rpBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rpBegin.pNext = NULL; rpBegin.renderPass = info.render_pass; rpBegin.framebuffer = info.framebuffers[info.current_buffer]; rpBegin.renderArea.offset.x = 0; rpBegin.renderArea.offset.y = 0; rpBegin.renderArea.extent.width = info.width; rpBegin.renderArea.extent.height = info.height; rpBegin.clearValueCount = 2; rpBegin.pClearValues = clear_values; VkCommandBufferBeginInfo cmdBufferInfo = {}; cmdBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; cmdBufferInfo.pNext = NULL; cmdBufferInfo.flags = 0; cmdBufferInfo.pInheritanceInfo = NULL; vkBeginCommandBuffer(info.cmd, &cmdBufferInfo); for (int x = 0; x < numBuffers; x++) { vkCmdBeginRenderPass(info.cmd, &rpBegin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline); vkCmdBindDescriptorSets(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, info.desc_set.data(), 0, NULL); const VkDeviceSize offsets[1] = {0}; vkCmdBindVertexBuffers(info.cmd, 0, 1, &info.vertex_buffer.buf, offsets); init_viewports(info); init_scissors(info); vkCmdDraw(info.cmd, 0, 1, 0, 0); vkCmdEndRenderPass(info.cmd); } res = vkEndCommandBuffer(info.cmd); ASSERT_EQ(VK_SUCCESS, res); const VkCommandBuffer cmd_bufs[] = {info.cmd}; VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submitInfo[1] = {}; submitInfo[0].pNext = NULL; submitInfo[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo[0].waitSemaphoreCount = 1; submitInfo[0].pWaitSemaphores = &imageAcquiredSemaphore; submitInfo[0].pWaitDstStageMask = &pipe_stage_flags; submitInfo[0].commandBufferCount = 1; submitInfo[0].pCommandBuffers = cmd_bufs; submitInfo[0].signalSemaphoreCount = 0; submitInfo[0].pSignalSemaphores = NULL; // Queue the command buffer for execution res = vkQueueSubmit(info.graphics_queue, 1, submitInfo, drawFence); ASSERT_EQ(VK_SUCCESS, res); Present(info, drawFence); } // 100 separate secondary cmd buffers, each with 1 Draw void SecondaryCommandBufferBenchmark(sample_info &info, VkClearValue *clear_values, VkFence drawFence, VkSemaphore imageAcquiredSemaphore, int numBuffers) { VkResult res; // Record Secondary Command Buffer VkCommandBufferInheritanceInfo inheritInfo = {}; inheritInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; inheritInfo.pNext = NULL; inheritInfo.renderPass = info.render_pass; inheritInfo.subpass = 0; inheritInfo.framebuffer = info.framebuffers[info.current_buffer]; inheritInfo.occlusionQueryEnable = false; inheritInfo.queryFlags = 0; inheritInfo.pipelineStatistics = 0; VkCommandBufferBeginInfo secondaryCommandBufferInfo = {}; secondaryCommandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; secondaryCommandBufferInfo.pNext = NULL; secondaryCommandBufferInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT | VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; secondaryCommandBufferInfo.pInheritanceInfo = &inheritInfo; for (int x = 0; x < numBuffers; x++) { vkBeginCommandBuffer(info.cmd2s[x], &secondaryCommandBufferInfo); vkCmdBindPipeline(info.cmd2s[x], VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline); vkCmdBindDescriptorSets(info.cmd2s[x], VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, info.desc_set.data(), 0, NULL); const VkDeviceSize offsets[1] = {0}; vkCmdBindVertexBuffers(info.cmd2s[x], 0, 1, &info.vertex_buffer.buf, offsets); init_viewports2_array(info, x); init_scissors2_array(info, x); vkCmdDraw(info.cmd2s[x], 0, 1, 0, 0); vkEndCommandBuffer(info.cmd2s[x]); } // Record Secondary Command Buffer End // Record Primary Command Buffer Begin VkRenderPassBeginInfo rpBegin; rpBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rpBegin.pNext = NULL; rpBegin.renderPass = info.render_pass; rpBegin.framebuffer = info.framebuffers[info.current_buffer]; rpBegin.renderArea.offset.x = 0; rpBegin.renderArea.offset.y = 0; rpBegin.renderArea.extent.width = info.width; rpBegin.renderArea.extent.height = info.height; rpBegin.clearValueCount = 2; rpBegin.pClearValues = clear_values; VkCommandBufferBeginInfo primaryCommandBufferInfo = {}; primaryCommandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; primaryCommandBufferInfo.pNext = NULL; primaryCommandBufferInfo.flags = 0; primaryCommandBufferInfo.pInheritanceInfo = NULL; vkBeginCommandBuffer(info.cmd, &primaryCommandBufferInfo); for (int x = 0; x < numBuffers; x++) { vkCmdBeginRenderPass(info.cmd, &rpBegin, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); vkCmdExecuteCommands(info.cmd, 1, &info.cmd2s[x]); vkCmdEndRenderPass(info.cmd); } vkEndCommandBuffer(info.cmd); // Record Primary Command Buffer End const VkCommandBuffer cmd_bufs[] = {info.cmd}; VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submitInfo[1] = {}; submitInfo[0].pNext = NULL; submitInfo[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo[0].waitSemaphoreCount = 1; submitInfo[0].pWaitSemaphores = &imageAcquiredSemaphore; submitInfo[0].pWaitDstStageMask = &pipe_stage_flags; submitInfo[0].commandBufferCount = 1; submitInfo[0].pCommandBuffers = cmd_bufs; submitInfo[0].signalSemaphoreCount = 0; submitInfo[0].pSignalSemaphores = NULL; // Queue the command buffer for execution res = vkQueueSubmit(info.graphics_queue, 1, submitInfo, drawFence); ASSERT_EQ(VK_SUCCESS, res); Present(info, drawFence); } // Details on the following functions that stress various cmd buffer reset methods. // All of these functions wrap the SecondaryCommandBufferBenchmark() test above, // adding additional overhead with various reset methods. // -CommandPoolDestroyBenchmark: Reset command buffers by destroying and re-creating // command buffer pool. // -CommandPoolHardResetBenchmark: Reset the command pool w/ the RELEASE_RESOURCES // bit set. // -CommandPoolSoftResetBenchmark: Reset to command pool w/o the RELEASE_RESOURCES // bit set. // -CommandBufferExplicitHardResetBenchmark: Reset each individual command buffer // w/ the RELEASE_RESOURCES bit set. // -CommandBufferExplicitSoftResetBenchmark: Reset each individual command buffer // w/o the RELEASE_RESOURCES bit set. // -CommandBufferImplicitResetBenchmark: Reset each individual command buffer // implicitly by calling "Begin" on previously used cmd buffer. void CommandPoolDestroyBenchmark(sample_info &info, VkClearValue *clear_values, VkFence drawFence, VkSemaphore imageAcquiredSemaphore, int numBuffers) { // Save setup cmd buffer data to be restored auto saved_cmd_pool = info.cmd_pool; auto saved_cb = info.cmd; auto saved_cb2s = info.cmd2s; // Now re-allocate & destroy cmd buffers to stress those calls init_command_pool(info, 0); init_command_buffer2_array(info, numBuffers); SecondaryCommandBufferBenchmark(info, clear_values, drawFence, imageAcquiredSemaphore, numBuffers); destroy_command_pool(info); // Restore original cmd buffer data for cleanup info.cmd_pool = saved_cmd_pool; info.cmd = saved_cb; info.cmd2s = saved_cb2s; } void CommandPoolHardResetBenchmark(sample_info &info, VkClearValue *clear_values, VkFence drawFence, VkSemaphore imageAcquiredSemaphore, int numBuffers) { SecondaryCommandBufferBenchmark(info, clear_values, drawFence, imageAcquiredSemaphore, numBuffers); reset_command_pool(info, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT); } void CommandPoolSoftResetBenchmark(sample_info &info, VkClearValue *clear_values, VkFence drawFence, VkSemaphore imageAcquiredSemaphore, int numBuffers) { SecondaryCommandBufferBenchmark(info, clear_values, drawFence, imageAcquiredSemaphore, numBuffers); reset_command_pool(info, 0); } void CommandBufferExplicitHardResetBenchmark(sample_info &info, VkClearValue *clear_values, VkFence drawFence, VkSemaphore imageAcquiredSemaphore, int numBuffers) { SecondaryCommandBufferBenchmark(info, clear_values, drawFence, imageAcquiredSemaphore, numBuffers); // Explicitly resetting cmd buffers reset_command_buffer2_array(info, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); } void CommandBufferExplicitSoftResetBenchmark(sample_info &info, VkClearValue *clear_values, VkFence drawFence, VkSemaphore imageAcquiredSemaphore, int numBuffers) { SecondaryCommandBufferBenchmark(info, clear_values, drawFence, imageAcquiredSemaphore, numBuffers); // Explicitly resetting cmd buffers w/ soft reset (don't release resources) reset_command_buffer2_array(info, 0); } void CommandBufferImplicitResetBenchmark(sample_info &info, VkClearValue *clear_values, VkFence drawFence, VkSemaphore imageAcquiredSemaphore, int numBuffers) { // Repeated call SCBBenchmark & BeginCmdBuffer calls will implicitly reset each cmd buffer SecondaryCommandBufferBenchmark(info, clear_values, drawFence, imageAcquiredSemaphore, numBuffers); } CommandBufferTestParams PrimaryCBHundredIndividualParams() { CommandBufferTestParams params; params.CBImplementation = PrimaryCommandBufferBenchmarkHundredIndividual; params.story = "_PrimaryCB_Submit_100_With_1_Draw"; return params; } CommandBufferTestParams PrimaryCBOneWithOneHundredParams() { CommandBufferTestParams params; params.CBImplementation = PrimaryCommandBufferBenchmarkOneWithOneHundred; params.story = "_PrimaryCB_Submit_1_With_100_Draw"; return params; } CommandBufferTestParams SecondaryCBParams() { CommandBufferTestParams params; params.CBImplementation = SecondaryCommandBufferBenchmark; params.story = "_SecondaryCB_Submit_1_With_100_Draw_In_Individual_Secondary"; return params; } CommandBufferTestParams CommandPoolDestroyParams() { CommandBufferTestParams params; params.CBImplementation = CommandPoolDestroyBenchmark; params.story = "_Reset_CBs_With_Destroy_Command_Pool"; return params; } CommandBufferTestParams CommandPoolHardResetParams() { CommandBufferTestParams params; params.CBImplementation = CommandPoolHardResetBenchmark; params.story = "_Reset_CBs_With_Hard_Reset_Command_Pool"; return params; } CommandBufferTestParams CommandPoolSoftResetParams() { CommandBufferTestParams params; params.CBImplementation = CommandPoolSoftResetBenchmark; params.story = "_Reset_CBs_With_Soft_Reset_Command_Pool"; return params; } CommandBufferTestParams CommandBufferExplicitHardResetParams() { CommandBufferTestParams params; params.CBImplementation = CommandBufferExplicitHardResetBenchmark; params.story = "_Reset_CBs_With_Explicit_Hard_Reset_Command_Buffers"; return params; } CommandBufferTestParams CommandBufferExplicitSoftResetParams() { CommandBufferTestParams params; params.CBImplementation = CommandBufferExplicitSoftResetBenchmark; params.story = "_Reset_CBs_With_Explicit_Soft_Reset_Command_Buffers"; return params; } CommandBufferTestParams CommandBufferImplicitResetParams() { CommandBufferTestParams params; params.CBImplementation = CommandBufferImplicitResetBenchmark; params.story = "_Reset_CBs_With_Implicit_Reset_Command_Buffers"; return params; } TEST_P(VulkanCommandBufferPerfTest, Run) { run(); } INSTANTIATE_TEST_SUITE_P(, VulkanCommandBufferPerfTest, ::testing::Values(PrimaryCBHundredIndividualParams(), PrimaryCBOneWithOneHundredParams(), SecondaryCBParams(), CommandPoolDestroyParams(), CommandPoolHardResetParams(), CommandPoolSoftResetParams(), CommandBufferExplicitHardResetParams(), CommandBufferExplicitSoftResetParams(), CommandBufferImplicitResetParams()));