Add microbenchmarks for vkCmdClear*Image
vkCmdClearColorImage() and vkCmdClearDepthStencilImage() are currently
implemented using Blitter::clear(), which delegates to fastClear() for
certain formats, or falls back to using a generic Reactor routine.
This change benchmarks the performance for:
- VK_FORMAT_R8G8B8A8_UNORM (fast path)
- VK_FORMAT_R32_SFLOAT (slow path)
- VK_FORMAT_D32_SFLOAT (slow path)
Bug: b/158231104
Change-Id: I5383b322e3ea5de6b21113843fb665a22a92b9bf
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/45470
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7a2d5a6..0e06e4e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -747,6 +747,7 @@
add_subdirectory(${TESTS_DIR}/ReactorBenchmarks) # Add ReactorBenchmarks target
add_subdirectory(${TESTS_DIR}/SystemBenchmarks) # Add system-benchmarks target
+ add_subdirectory(${TESTS_DIR}/VulkanBenchmarks) # Add VulkanBenchmarks target
endif()
if(SWIFTSHADER_BUILD_TESTS AND SWIFTSHADER_BUILD_VULKAN)
diff --git a/tests/VulkanBenchmarks/CMakeLists.txt b/tests/VulkanBenchmarks/CMakeLists.txt
new file mode 100644
index 0000000..783b1ea
--- /dev/null
+++ b/tests/VulkanBenchmarks/CMakeLists.txt
@@ -0,0 +1,66 @@
+# Copyright 2020 The SwiftShader Authors. 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
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(ROOT_PROJECT_COMPILE_OPTIONS
+ ${SWIFTSHADER_COMPILE_OPTIONS}
+ ${WARNINGS_AS_ERRORS}
+)
+
+set(ROOT_PROJECT_LINK_LIBRARIES
+ ${OS_LIBS}
+ ${SWIFTSHADER_LIBS}
+)
+
+set(VULKAN_BENCHMARKS_SRC_FILES
+ VulkanBenchmarks.cpp
+ main.cpp
+)
+
+add_executable(VulkanBenchmarks
+ ${VULKAN_BENCHMARKS_SRC_FILES}
+)
+
+if (NOT TARGET benchmark::benchmark)
+ message(FATAL_ERROR "Missing required target: benchmark::benchmark")
+endif()
+
+add_dependencies(VulkanBenchmarks
+ vk_swiftshader
+)
+
+set_target_properties(VulkanBenchmarks PROPERTIES
+ FOLDER "Benchmarks"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
+)
+
+target_include_directories(VulkanBenchmarks
+ PRIVATE
+ "${SWIFTSHADER_DIR}/include"
+)
+
+target_compile_options(VulkanBenchmarks
+ PRIVATE
+ ${ROOT_PROJECT_COMPILE_OPTIONS}
+)
+
+target_link_options(VulkanBenchmarks
+ PRIVATE
+ ${SWIFTSHADER_LINK_FLAGS}
+)
+
+target_link_libraries(VulkanBenchmarks
+ PRIVATE
+ benchmark::benchmark
+ ${ROOT_PROJECT_LINK_LIBRARIES}
+)
diff --git a/tests/VulkanBenchmarks/VulkanBenchmarks.cpp b/tests/VulkanBenchmarks/VulkanBenchmarks.cpp
new file mode 100644
index 0000000..5f8fd37
--- /dev/null
+++ b/tests/VulkanBenchmarks/VulkanBenchmarks.cpp
@@ -0,0 +1,201 @@
+// Copyright 2020 The SwiftShader Authors. 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "benchmark/benchmark.h"
+
+#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
+#include <vulkan/vulkan.hpp>
+VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
+
+#include <cassert>
+#include <vector>
+
+class VulkanBenchmark : public benchmark::Fixture
+{
+public:
+ void SetUp(::benchmark::State &state) override
+ {
+ // TODO(b/158231104): Other platforms
+ dl = std::make_unique<vk::DynamicLoader>("./vk_swiftshader.dll");
+ assert(dl->success());
+
+ PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl->getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
+ VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
+
+ instance = vk::createInstance({}, nullptr);
+ VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
+
+ std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
+ assert(!physicalDevices.empty());
+
+ const float defaultQueuePriority = 0.0f;
+ vk::DeviceQueueCreateInfo queueCreatInfo;
+ queueCreatInfo.queueFamilyIndex = queueFamilyIndex;
+ queueCreatInfo.queueCount = 1;
+ queueCreatInfo.pQueuePriorities = &defaultQueuePriority;
+
+ vk::DeviceCreateInfo deviceCreateInfo;
+ deviceCreateInfo.queueCreateInfoCount = 1;
+ deviceCreateInfo.pQueueCreateInfos = &queueCreatInfo;
+
+ device = physicalDevices[0].createDevice(deviceCreateInfo, nullptr);
+
+ queue = device.getQueue(queueFamilyIndex, 0);
+ }
+
+ void TearDown(const ::benchmark::State &state) override
+ {
+ device.waitIdle();
+ device.destroy();
+ instance.destroy();
+ }
+
+protected:
+ const uint32_t queueFamilyIndex = 0;
+
+ vk::Instance instance;
+ vk::Device device;
+ vk::Queue queue;
+
+private:
+ std::unique_ptr<vk::DynamicLoader> dl;
+};
+
+struct ClearBenchmarkVariant
+{
+ vk::Format format;
+ const char *formatName;
+ vk::ImageAspectFlags aspect;
+};
+
+const std::vector<ClearBenchmarkVariant> clearBenchmarkVariants = {
+ { vk::Format::eR8G8B8A8Unorm, "VK_FORMAT_R8G8B8A8_UNORM", vk::ImageAspectFlagBits::eColor },
+ { vk::Format::eR32Sfloat, "VK_FORMAT_R32_SFLOAT", vk::ImageAspectFlagBits::eColor },
+ { vk::Format::eD32Sfloat, "VK_FORMAT_D32_SFLOAT", vk::ImageAspectFlagBits::eDepth },
+};
+
+class ClearImageBenchmark : public VulkanBenchmark
+{
+public:
+ void SetUp(::benchmark::State &state) override
+ {
+ VulkanBenchmark::SetUp(state);
+
+ benchmark = clearBenchmarkVariants[state.range(0)];
+ state.counters[benchmark.formatName] = 1; // Small hack to display the format's name.
+ }
+
+ void TearDown(const ::benchmark::State &state) override
+ {
+ VulkanBenchmark::TearDown(state);
+ }
+
+protected:
+ ClearBenchmarkVariant benchmark;
+};
+
+BENCHMARK_DEFINE_F(ClearImageBenchmark, Clear)
+(benchmark::State &state)
+{
+ vk::ImageCreateInfo imageInfo;
+ imageInfo.imageType = vk::ImageType::e2D;
+ imageInfo.format = benchmark.format;
+ imageInfo.tiling = vk::ImageTiling::eOptimal;
+ imageInfo.initialLayout = vk::ImageLayout::eGeneral;
+ imageInfo.usage = vk::ImageUsageFlagBits::eTransferDst;
+ imageInfo.samples = vk::SampleCountFlagBits::e4;
+ imageInfo.extent = { 1024, 1024, 1 };
+ imageInfo.mipLevels = 1;
+ imageInfo.arrayLayers = 1;
+
+ vk::Image image = device.createImage(imageInfo);
+
+ vk::MemoryRequirements memoryRequirements = device.getImageMemoryRequirements(image);
+
+ vk::MemoryAllocateInfo allocateInfo;
+ allocateInfo.allocationSize = memoryRequirements.size;
+ allocateInfo.memoryTypeIndex = 0;
+
+ vk::DeviceMemory memory = device.allocateMemory(allocateInfo);
+
+ device.bindImageMemory(image, memory, 0);
+
+ vk::CommandPoolCreateInfo commandPoolCreateInfo;
+ commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex;
+
+ vk::CommandPool commandPool = device.createCommandPool(commandPoolCreateInfo);
+
+ vk::CommandBufferAllocateInfo commandBufferAllocateInfo;
+ commandBufferAllocateInfo.commandPool = commandPool;
+ commandBufferAllocateInfo.commandBufferCount = 1;
+
+ vk::CommandBuffer commandBuffer = device.allocateCommandBuffers(commandBufferAllocateInfo)[0];
+
+ vk::CommandBufferBeginInfo commandBufferBeginInfo;
+ commandBufferBeginInfo.flags = {};
+
+ commandBuffer.begin(commandBufferBeginInfo);
+
+ vk::ImageSubresourceRange range;
+ range.aspectMask = benchmark.aspect;
+ range.baseMipLevel = 0;
+ range.levelCount = 1;
+ range.baseArrayLayer = 0;
+ range.layerCount = 1;
+
+ if(benchmark.aspect == vk::ImageAspectFlagBits::eColor)
+ {
+ vk::ClearColorValue clearColorValue;
+ clearColorValue.float32[0] = 0.0f;
+ clearColorValue.float32[1] = 1.0f;
+ clearColorValue.float32[2] = 0.0f;
+ clearColorValue.float32[3] = 1.0f;
+
+ commandBuffer.clearColorImage(image, vk::ImageLayout::eGeneral, &clearColorValue, 1, &range);
+ }
+ else if(benchmark.aspect == vk::ImageAspectFlagBits::eDepth)
+ {
+ vk::ClearDepthStencilValue clearDepthStencilValue;
+ clearDepthStencilValue.depth = 1.0f;
+ clearDepthStencilValue.stencil = 0xFF;
+
+ commandBuffer.clearDepthStencilImage(image, vk::ImageLayout::eGeneral, &clearDepthStencilValue, 1, &range);
+ }
+ else
+ assert(false);
+
+ commandBuffer.end();
+
+ vk::SubmitInfo submitInfo;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &commandBuffer;
+
+ // Execute once to have the Reactor routine generated.
+ queue.submit(1, &submitInfo, nullptr);
+ queue.waitIdle();
+
+ for(auto _ : state)
+ {
+ queue.submit(1, &submitInfo, nullptr);
+ queue.waitIdle();
+ }
+
+ device.freeCommandBuffers(commandPool, { commandBuffer });
+ device.destroyCommandPool(commandPool);
+ device.freeMemory(memory);
+ device.destroyImage(image);
+}
+BENCHMARK_REGISTER_F(ClearImageBenchmark, Clear)
+ ->Unit(benchmark::kMillisecond)
+ ->DenseRange(0, clearBenchmarkVariants.size() - 1, 1);
diff --git a/tests/VulkanBenchmarks/main.cpp b/tests/VulkanBenchmarks/main.cpp
new file mode 100644
index 0000000..9f307ab
--- /dev/null
+++ b/tests/VulkanBenchmarks/main.cpp
@@ -0,0 +1,17 @@
+// Copyright 2020 The SwiftShader Authors. 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
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "benchmark/benchmark.h"
+
+BENCHMARK_MAIN();