Add a benchmark with multisampling enabled
This refactors the benchmarks to use static functions which support
passing arbitrary arguments, instead of fixtures:
https://github.com/google/benchmark#passing-arbitrary-arguments-to-a-benchmark
This makes it easier to have a variant with and without multisampling,
and avoids using state.counters[] as a hack to display clear formats.
Bug: b/158231104
Change-Id: Icf0eed254dc942af8f2bcfc975a1e5e581b6e786
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/45790
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/tests/VulkanBenchmarks/VulkanBenchmarks.cpp b/tests/VulkanBenchmarks/VulkanBenchmarks.cpp
index e228aed..fd0fb84 100644
--- a/tests/VulkanBenchmarks/VulkanBenchmarks.cpp
+++ b/tests/VulkanBenchmarks/VulkanBenchmarks.cpp
@@ -29,10 +29,10 @@
#include <cassert>
#include <vector>
-class VulkanBenchmark : public benchmark::Fixture
+class VulkanBenchmark
{
public:
- void SetUp(::benchmark::State &state) override
+ VulkanBenchmark()
{
// TODO(b/158231104): Other platforms
dl = std::make_unique<vk::DynamicLoader>("./vk_swiftshader.dll");
@@ -63,7 +63,7 @@
queue = device.getQueue(queueFamilyIndex, 0);
}
- void TearDown(const ::benchmark::State &state) override
+ virtual ~VulkanBenchmark()
{
device.waitIdle();
device.destroy();
@@ -101,133 +101,122 @@
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
+ ClearImageBenchmark(vk::Format clearFormat, vk::ImageAspectFlagBits clearAspect)
{
- VulkanBenchmark::SetUp(state);
+ vk::ImageCreateInfo imageInfo;
+ imageInfo.imageType = vk::ImageType::e2D;
+ imageInfo.format = clearFormat;
+ 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;
- benchmark = clearBenchmarkVariants[state.range(0)];
- state.counters[benchmark.formatName] = 1; // Small hack to display the format's name.
+ image = device.createImage(imageInfo);
+
+ vk::MemoryRequirements memoryRequirements = device.getImageMemoryRequirements(image);
+
+ vk::MemoryAllocateInfo allocateInfo;
+ allocateInfo.allocationSize = memoryRequirements.size;
+ allocateInfo.memoryTypeIndex = 0;
+
+ memory = device.allocateMemory(allocateInfo);
+
+ device.bindImageMemory(image, memory, 0);
+
+ vk::CommandPoolCreateInfo commandPoolCreateInfo;
+ commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex;
+
+ commandPool = device.createCommandPool(commandPoolCreateInfo);
+
+ vk::CommandBufferAllocateInfo commandBufferAllocateInfo;
+ commandBufferAllocateInfo.commandPool = commandPool;
+ commandBufferAllocateInfo.commandBufferCount = 1;
+
+ commandBuffer = device.allocateCommandBuffers(commandBufferAllocateInfo)[0];
+
+ vk::CommandBufferBeginInfo commandBufferBeginInfo;
+ commandBufferBeginInfo.flags = {};
+
+ commandBuffer.begin(commandBufferBeginInfo);
+
+ vk::ImageSubresourceRange range;
+ range.aspectMask = clearAspect;
+ range.baseMipLevel = 0;
+ range.levelCount = 1;
+ range.baseArrayLayer = 0;
+ range.layerCount = 1;
+
+ if(clearAspect == 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(clearAspect == 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();
}
- void TearDown(const ::benchmark::State &state) override
+ ~ClearImageBenchmark()
{
- VulkanBenchmark::TearDown(state);
+ device.freeCommandBuffers(commandPool, { commandBuffer });
+ device.destroyCommandPool(commandPool);
+ device.freeMemory(memory);
+ device.destroyImage(image);
}
-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)
+ void clear()
{
- vk::ClearColorValue clearColorValue;
- clearColorValue.float32[0] = 0.0f;
- clearColorValue.float32[1] = 1.0f;
- clearColorValue.float32[2] = 0.0f;
- clearColorValue.float32[3] = 1.0f;
+ vk::SubmitInfo submitInfo;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &commandBuffer;
- 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);
+private:
+ vk::CommandPool commandPool;
+ vk::CommandBuffer commandBuffer;
+
+ vk::Image image;
+ vk::DeviceMemory memory;
+};
+
+static void ClearImage(benchmark::State &state, vk::Format clearFormat, vk::ImageAspectFlagBits clearAspect)
+{
+ ClearImageBenchmark benchmark(clearFormat, clearAspect);
+
+ // Execute once to have the Reactor routine generated.
+ benchmark.clear();
+
+ for(auto _ : state)
+ {
+ benchmark.clear();
+ }
}
-BENCHMARK_REGISTER_F(ClearImageBenchmark, Clear)
- ->Unit(benchmark::kMillisecond)
- ->DenseRange(0, clearBenchmarkVariants.size() - 1, 1);
+BENCHMARK_CAPTURE(ClearImage, VK_FORMAT_R8G8B8A8_UNORM, vk::Format::eR8G8B8A8Unorm, vk::ImageAspectFlagBits::eColor)->Unit(benchmark::kMillisecond);
+BENCHMARK_CAPTURE(ClearImage, VK_FORMAT_R32_SFLOAT, vk::Format::eR32Sfloat, vk::ImageAspectFlagBits::eColor)->Unit(benchmark::kMillisecond);
+BENCHMARK_CAPTURE(ClearImage, VK_FORMAT_D32_SFLOAT, vk::Format::eD32Sfloat, vk::ImageAspectFlagBits::eDepth)->Unit(benchmark::kMillisecond);
class Window
{
@@ -541,10 +530,9 @@
class TriangleBenchmark : public VulkanBenchmark
{
public:
- void SetUp(::benchmark::State &state) override
+ TriangleBenchmark(bool multisample)
+ : multisample(multisample)
{
- VulkanBenchmark::SetUp(state);
-
window = new Window(instance, windowSize);
swapchain = new Swapchain(physicalDevice, device, window);
@@ -560,7 +548,7 @@
createCommandBuffers(renderPass);
}
- void TearDown(const ::benchmark::State &state) override
+ ~TriangleBenchmark()
{
device.destroyPipelineLayout(pipelineLayout);
device.destroyPipelineCache(pipelineCache);
@@ -588,8 +576,34 @@
delete swapchain;
delete window;
+ }
- VulkanBenchmark::TearDown(state);
+ void renderFrame()
+ {
+ swapchain->acquireNextImage(presentCompleteSemaphore, currentFrameBuffer);
+
+ device.waitForFences(1, &waitFences[currentFrameBuffer], VK_TRUE, UINT64_MAX);
+ device.resetFences(1, &waitFences[currentFrameBuffer]);
+
+ vk::PipelineStageFlags waitStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
+
+ vk::SubmitInfo submitInfo;
+ submitInfo.pWaitDstStageMask = &waitStageMask;
+ submitInfo.pWaitSemaphores = &presentCompleteSemaphore;
+ submitInfo.waitSemaphoreCount = 1;
+ submitInfo.pSignalSemaphores = &renderCompleteSemaphore;
+ submitInfo.signalSemaphoreCount = 1;
+ submitInfo.pCommandBuffers = &commandBuffers[currentFrameBuffer];
+ submitInfo.commandBufferCount = 1;
+
+ queue.submit(1, &submitInfo, waitFences[currentFrameBuffer]);
+
+ swapchain->queuePresent(queue, currentFrameBuffer, renderCompleteSemaphore);
+ }
+
+ void show()
+ {
+ window->show();
}
protected:
@@ -657,29 +671,6 @@
}
}
- void renderFrame()
- {
- swapchain->acquireNextImage(presentCompleteSemaphore, currentFrameBuffer);
-
- device.waitForFences(1, &waitFences[currentFrameBuffer], VK_TRUE, UINT64_MAX);
- device.resetFences(1, &waitFences[currentFrameBuffer]);
-
- vk::PipelineStageFlags waitStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
-
- vk::SubmitInfo submitInfo;
- submitInfo.pWaitDstStageMask = &waitStageMask;
- submitInfo.pWaitSemaphores = &presentCompleteSemaphore;
- submitInfo.waitSemaphoreCount = 1;
- submitInfo.pSignalSemaphores = &renderCompleteSemaphore;
- submitInfo.signalSemaphoreCount = 1;
- submitInfo.pCommandBuffers = &commandBuffers[currentFrameBuffer];
- submitInfo.commandBufferCount = 1;
-
- queue.submit(1, &submitInfo, waitFences[currentFrameBuffer]);
-
- swapchain->queuePresent(queue, currentFrameBuffer, renderCompleteSemaphore);
- }
-
void prepareVertices()
{
struct Vertex
@@ -933,7 +924,7 @@
}
const vk::Extent2D windowSize = { 1280, 720 };
- const bool multisample = false;
+ const bool multisample;
Window *window = nullptr;
Swapchain *swapchain = nullptr;
@@ -965,18 +956,19 @@
std::vector<vk::Fence> waitFences;
};
-BENCHMARK_DEFINE_F(TriangleBenchmark, Triangle)
-(benchmark::State &state)
+static void Triangle(benchmark::State &state, bool multisample)
{
- if(false) window->show(); // Enable for visual verification.
+ TriangleBenchmark benchmark(multisample);
+
+ if(false) benchmark.show(); // Enable for visual verification.
// Warmup
- renderFrame();
+ benchmark.renderFrame();
for(auto _ : state)
{
- renderFrame();
+ benchmark.renderFrame();
}
}
-BENCHMARK_REGISTER_F(TriangleBenchmark, Triangle)
- ->Unit(benchmark::kMillisecond);
+BENCHMARK_CAPTURE(Triangle, Hello, false)->Unit(benchmark::kMillisecond);
+BENCHMARK_CAPTURE(Triangle, Multisample, true)->Unit(benchmark::kMillisecond);