1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // VulkanPipelineCachePerf:
7 // Performance benchmark for the Vulkan Pipeline cache.
8
9 #include "ANGLEPerfTest.h"
10
11 #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
12 #include "libANGLE/renderer/vulkan/vk_helpers.h"
13 #include "libANGLE/renderer/vulkan/vk_renderer.h"
14 #include "util/random_utils.h"
15
16 using namespace rx;
17
18 namespace
19 {
20 constexpr unsigned int kIterationsPerStep = 100;
21
22 struct Params
23 {
24 bool withDynamicState = false;
25 };
26
27 class VulkanPipelineCachePerfTest : public ANGLEPerfTest,
28 public ::testing::WithParamInterface<Params>
29 {
30 public:
31 VulkanPipelineCachePerfTest();
32 ~VulkanPipelineCachePerfTest();
33
34 void SetUp() override;
35 void step() override;
36
37 GraphicsPipelineCache<GraphicsPipelineDescCompleteHash> mCache;
38 angle::RNG mRNG;
39
40 std::vector<vk::GraphicsPipelineDesc> mCacheHits;
41 std::vector<vk::GraphicsPipelineDesc> mCacheMisses;
42 size_t mMissIndex = 0;
43
44 private:
45 void randomizeDesc(vk::GraphicsPipelineDesc *desc);
46 };
47
VulkanPipelineCachePerfTest()48 VulkanPipelineCachePerfTest::VulkanPipelineCachePerfTest()
49 : ANGLEPerfTest("VulkanPipelineCachePerf", "", "", kIterationsPerStep), mRNG(0x12345678u)
50 {}
51
~VulkanPipelineCachePerfTest()52 VulkanPipelineCachePerfTest::~VulkanPipelineCachePerfTest()
53 {
54 mCache.reset();
55 }
56
SetUp()57 void VulkanPipelineCachePerfTest::SetUp()
58 {
59 ANGLEPerfTest::SetUp();
60
61 // Insert a number of random pipeline states.
62 for (int pipelineCount = 0; pipelineCount < 100; ++pipelineCount)
63 {
64 vk::Pipeline pipeline;
65 vk::GraphicsPipelineDesc desc;
66 randomizeDesc(&desc);
67
68 if (pipelineCount < 10)
69 {
70 mCacheHits.push_back(desc);
71 }
72 mCache.populate(desc, std::move(pipeline), nullptr);
73 }
74
75 for (int missCount = 0; missCount < 10000; ++missCount)
76 {
77 vk::GraphicsPipelineDesc desc;
78 randomizeDesc(&desc);
79 mCacheMisses.push_back(desc);
80 }
81 }
82
randomizeDesc(vk::GraphicsPipelineDesc * desc)83 void VulkanPipelineCachePerfTest::randomizeDesc(vk::GraphicsPipelineDesc *desc)
84 {
85 std::vector<uint8_t> bytes(sizeof(vk::GraphicsPipelineDesc));
86 FillVectorWithRandomUBytes(&mRNG, &bytes);
87 memcpy(desc, bytes.data(), sizeof(vk::GraphicsPipelineDesc));
88
89 desc->setSupportsDynamicStateForTest(GetParam().withDynamicState);
90 }
91
step()92 void VulkanPipelineCachePerfTest::step()
93 {
94 vk::RenderPass rp;
95 vk::PipelineLayout pl;
96 vk::PipelineCache pc;
97 vk::PipelineCacheAccess spc;
98 vk::ShaderModulePtr vs = vk::ShaderModulePtr::MakeShared(VK_NULL_HANDLE);
99 vk::ShaderModulePtr fs = vk::ShaderModulePtr::MakeShared(VK_NULL_HANDLE);
100 vk::ShaderModuleMap ssm;
101 const vk::GraphicsPipelineDesc *desc = nullptr;
102 vk::PipelineHelper *result = nullptr;
103
104 // The Vulkan handle types are difficult to cast to without #ifdefs.
105 vs->setHandle((VkShaderModule)1);
106 fs->setHandle((VkShaderModule)2);
107
108 ssm[gl::ShaderType::Vertex] = vs;
109 ssm[gl::ShaderType::Fragment] = fs;
110
111 spc.init(&pc, nullptr);
112
113 vk::SpecializationConstants defaultSpecConsts{};
114
115 for (unsigned int iteration = 0; iteration < kIterationsPerStep; ++iteration)
116 {
117 for (const auto &hit : mCacheHits)
118 {
119 if (!mCache.getPipeline(hit, &desc, &result))
120 {
121 (void)mCache.createPipeline(VK_NULL_HANDLE, &spc, rp, pl, ssm, defaultSpecConsts,
122 PipelineSource::Draw, hit, &desc, &result);
123 }
124 }
125 }
126
127 for (int missCount = 0; missCount < 20 && mMissIndex < mCacheMisses.size();
128 ++missCount, ++mMissIndex)
129 {
130 const auto &miss = mCacheMisses[mMissIndex];
131 if (!mCache.getPipeline(miss, &desc, &result))
132 {
133 (void)mCache.createPipeline(VK_NULL_HANDLE, &spc, rp, pl, ssm, defaultSpecConsts,
134 PipelineSource::Draw, miss, &desc, &result);
135 }
136 }
137
138 vs->setHandle(VK_NULL_HANDLE);
139 fs->setHandle(VK_NULL_HANDLE);
140 }
141
142 } // anonymous namespace
143
144 // Test performance of pipeline hash and look up in Vulkan
TEST_P(VulkanPipelineCachePerfTest,Run)145 TEST_P(VulkanPipelineCachePerfTest, Run)
146 {
147 run();
148 }
149
150 INSTANTIATE_TEST_SUITE_P(,
151 VulkanPipelineCachePerfTest,
152 ::testing::ValuesIn(std::vector<Params>{{Params{false}, Params{true}}}));
153