Commit 7a1d99d0 by Nicolas Capens Committed by Nicolas Capens

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: 's avatarNicolas Capens <nicolascapens@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarAntonio Maiorano <amaiorano@google.com>
parent 7975aa43
...@@ -29,10 +29,10 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE ...@@ -29,10 +29,10 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include <cassert> #include <cassert>
#include <vector> #include <vector>
class VulkanBenchmark : public benchmark::Fixture class VulkanBenchmark
{ {
public: public:
void SetUp(::benchmark::State &state) override VulkanBenchmark()
{ {
// TODO(b/158231104): Other platforms // TODO(b/158231104): Other platforms
dl = std::make_unique<vk::DynamicLoader>("./vk_swiftshader.dll"); dl = std::make_unique<vk::DynamicLoader>("./vk_swiftshader.dll");
...@@ -63,7 +63,7 @@ public: ...@@ -63,7 +63,7 @@ public:
queue = device.getQueue(queueFamilyIndex, 0); queue = device.getQueue(queueFamilyIndex, 0);
} }
void TearDown(const ::benchmark::State &state) override virtual ~VulkanBenchmark()
{ {
device.waitIdle(); device.waitIdle();
device.destroy(); device.destroy();
...@@ -101,133 +101,122 @@ private: ...@@ -101,133 +101,122 @@ private:
std::unique_ptr<vk::DynamicLoader> dl; 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 class ClearImageBenchmark : public VulkanBenchmark
{ {
public: 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)]; image = device.createImage(imageInfo);
state.counters[benchmark.formatName] = 1; // Small hack to display the format's name.
}
void TearDown(const ::benchmark::State &state) override vk::MemoryRequirements memoryRequirements = device.getImageMemoryRequirements(image);
{
VulkanBenchmark::TearDown(state);
}
protected: vk::MemoryAllocateInfo allocateInfo;
ClearBenchmarkVariant benchmark; allocateInfo.allocationSize = memoryRequirements.size;
}; allocateInfo.memoryTypeIndex = 0;
BENCHMARK_DEFINE_F(ClearImageBenchmark, Clear) memory = device.allocateMemory(allocateInfo);
(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); device.bindImageMemory(image, memory, 0);
vk::MemoryRequirements memoryRequirements = device.getImageMemoryRequirements(image); vk::CommandPoolCreateInfo commandPoolCreateInfo;
commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex;
vk::MemoryAllocateInfo allocateInfo; commandPool = device.createCommandPool(commandPoolCreateInfo);
allocateInfo.allocationSize = memoryRequirements.size;
allocateInfo.memoryTypeIndex = 0;
vk::DeviceMemory memory = device.allocateMemory(allocateInfo); vk::CommandBufferAllocateInfo commandBufferAllocateInfo;
commandBufferAllocateInfo.commandPool = commandPool;
commandBufferAllocateInfo.commandBufferCount = 1;
device.bindImageMemory(image, memory, 0); commandBuffer = device.allocateCommandBuffers(commandBufferAllocateInfo)[0];
vk::CommandPoolCreateInfo commandPoolCreateInfo; vk::CommandBufferBeginInfo commandBufferBeginInfo;
commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex; commandBufferBeginInfo.flags = {};
vk::CommandPool commandPool = device.createCommandPool(commandPoolCreateInfo); commandBuffer.begin(commandBufferBeginInfo);
vk::CommandBufferAllocateInfo commandBufferAllocateInfo; vk::ImageSubresourceRange range;
commandBufferAllocateInfo.commandPool = commandPool; range.aspectMask = clearAspect;
commandBufferAllocateInfo.commandBufferCount = 1; range.baseMipLevel = 0;
range.levelCount = 1;
range.baseArrayLayer = 0;
range.layerCount = 1;
vk::CommandBuffer commandBuffer = device.allocateCommandBuffers(commandBufferAllocateInfo)[0]; 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;
vk::CommandBufferBeginInfo commandBufferBeginInfo; commandBuffer.clearColorImage(image, vk::ImageLayout::eGeneral, &clearColorValue, 1, &range);
commandBufferBeginInfo.flags = {}; }
else if(clearAspect == vk::ImageAspectFlagBits::eDepth)
{
vk::ClearDepthStencilValue clearDepthStencilValue;
clearDepthStencilValue.depth = 1.0f;
clearDepthStencilValue.stencil = 0xFF;
commandBuffer.begin(commandBufferBeginInfo); commandBuffer.clearDepthStencilImage(image, vk::ImageLayout::eGeneral, &clearDepthStencilValue, 1, &range);
}
else
assert(false);
vk::ImageSubresourceRange range; commandBuffer.end();
range.aspectMask = benchmark.aspect; }
range.baseMipLevel = 0;
range.levelCount = 1;
range.baseArrayLayer = 0;
range.layerCount = 1;
if(benchmark.aspect == vk::ImageAspectFlagBits::eColor) ~ClearImageBenchmark()
{ {
vk::ClearColorValue clearColorValue; device.freeCommandBuffers(commandPool, { commandBuffer });
clearColorValue.float32[0] = 0.0f; device.destroyCommandPool(commandPool);
clearColorValue.float32[1] = 1.0f; device.freeMemory(memory);
clearColorValue.float32[2] = 0.0f; device.destroyImage(image);
clearColorValue.float32[3] = 1.0f;
commandBuffer.clearColorImage(image, vk::ImageLayout::eGeneral, &clearColorValue, 1, &range);
} }
else if(benchmark.aspect == vk::ImageAspectFlagBits::eDepth)
void clear()
{ {
vk::ClearDepthStencilValue clearDepthStencilValue; vk::SubmitInfo submitInfo;
clearDepthStencilValue.depth = 1.0f; submitInfo.commandBufferCount = 1;
clearDepthStencilValue.stencil = 0xFF; submitInfo.pCommandBuffers = &commandBuffer;
commandBuffer.clearDepthStencilImage(image, vk::ImageLayout::eGeneral, &clearDepthStencilValue, 1, &range); queue.submit(1, &submitInfo, nullptr);
queue.waitIdle();
} }
else
assert(false);
commandBuffer.end(); private:
vk::CommandPool commandPool;
vk::CommandBuffer commandBuffer;
vk::Image image;
vk::DeviceMemory memory;
};
vk::SubmitInfo submitInfo; static void ClearImage(benchmark::State &state, vk::Format clearFormat, vk::ImageAspectFlagBits clearAspect)
submitInfo.commandBufferCount = 1; {
submitInfo.pCommandBuffers = &commandBuffer; ClearImageBenchmark benchmark(clearFormat, clearAspect);
// Execute once to have the Reactor routine generated. // Execute once to have the Reactor routine generated.
queue.submit(1, &submitInfo, nullptr); benchmark.clear();
queue.waitIdle();
for(auto _ : state) for(auto _ : state)
{ {
queue.submit(1, &submitInfo, nullptr); benchmark.clear();
queue.waitIdle();
} }
device.freeCommandBuffers(commandPool, { commandBuffer });
device.destroyCommandPool(commandPool);
device.freeMemory(memory);
device.destroyImage(image);
} }
BENCHMARK_REGISTER_F(ClearImageBenchmark, Clear) BENCHMARK_CAPTURE(ClearImage, VK_FORMAT_R8G8B8A8_UNORM, vk::Format::eR8G8B8A8Unorm, vk::ImageAspectFlagBits::eColor)->Unit(benchmark::kMillisecond);
->Unit(benchmark::kMillisecond) BENCHMARK_CAPTURE(ClearImage, VK_FORMAT_R32_SFLOAT, vk::Format::eR32Sfloat, vk::ImageAspectFlagBits::eColor)->Unit(benchmark::kMillisecond);
->DenseRange(0, clearBenchmarkVariants.size() - 1, 1); BENCHMARK_CAPTURE(ClearImage, VK_FORMAT_D32_SFLOAT, vk::Format::eD32Sfloat, vk::ImageAspectFlagBits::eDepth)->Unit(benchmark::kMillisecond);
class Window class Window
{ {
...@@ -541,10 +530,9 @@ static std::vector<uint32_t> compileGLSLtoSPIRV(const char *glslSource, EShLangu ...@@ -541,10 +530,9 @@ static std::vector<uint32_t> compileGLSLtoSPIRV(const char *glslSource, EShLangu
class TriangleBenchmark : public VulkanBenchmark class TriangleBenchmark : public VulkanBenchmark
{ {
public: public:
void SetUp(::benchmark::State &state) override TriangleBenchmark(bool multisample)
: multisample(multisample)
{ {
VulkanBenchmark::SetUp(state);
window = new Window(instance, windowSize); window = new Window(instance, windowSize);
swapchain = new Swapchain(physicalDevice, device, window); swapchain = new Swapchain(physicalDevice, device, window);
...@@ -560,7 +548,7 @@ public: ...@@ -560,7 +548,7 @@ public:
createCommandBuffers(renderPass); createCommandBuffers(renderPass);
} }
void TearDown(const ::benchmark::State &state) override ~TriangleBenchmark()
{ {
device.destroyPipelineLayout(pipelineLayout); device.destroyPipelineLayout(pipelineLayout);
device.destroyPipelineCache(pipelineCache); device.destroyPipelineCache(pipelineCache);
...@@ -588,8 +576,34 @@ public: ...@@ -588,8 +576,34 @@ public:
delete swapchain; delete swapchain;
delete window; delete window;
}
void renderFrame()
{
swapchain->acquireNextImage(presentCompleteSemaphore, currentFrameBuffer);
VulkanBenchmark::TearDown(state); 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: protected:
...@@ -657,29 +671,6 @@ protected: ...@@ -657,29 +671,6 @@ protected:
} }
} }
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() void prepareVertices()
{ {
struct Vertex struct Vertex
...@@ -933,7 +924,7 @@ protected: ...@@ -933,7 +924,7 @@ protected:
} }
const vk::Extent2D windowSize = { 1280, 720 }; const vk::Extent2D windowSize = { 1280, 720 };
const bool multisample = false; const bool multisample;
Window *window = nullptr; Window *window = nullptr;
Swapchain *swapchain = nullptr; Swapchain *swapchain = nullptr;
...@@ -965,18 +956,19 @@ protected: ...@@ -965,18 +956,19 @@ protected:
std::vector<vk::Fence> waitFences; std::vector<vk::Fence> waitFences;
}; };
BENCHMARK_DEFINE_F(TriangleBenchmark, Triangle) static void Triangle(benchmark::State &state, bool multisample)
(benchmark::State &state)
{ {
if(false) window->show(); // Enable for visual verification. TriangleBenchmark benchmark(multisample);
if(false) benchmark.show(); // Enable for visual verification.
// Warmup // Warmup
renderFrame(); benchmark.renderFrame();
for(auto _ : state) for(auto _ : state)
{ {
renderFrame(); benchmark.renderFrame();
} }
} }
BENCHMARK_REGISTER_F(TriangleBenchmark, Triangle) BENCHMARK_CAPTURE(Triangle, Hello, false)->Unit(benchmark::kMillisecond);
->Unit(benchmark::kMillisecond); BENCHMARK_CAPTURE(Triangle, Multisample, true)->Unit(benchmark::kMillisecond);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment