Hash :
7b4b56f0
Author :
Date :
2022-10-19T00:05:22
Vulkan: Missing output mask in GraphicsPipelineDesc Currently, there's some program state used in creating pipelines alongside what's in GraphicsPipelineDesc. This works because the pipeline cache lives in the program executable. With VK_EXT_graphics_pipeline_library however, we could create vertex input and fragment output partial pipelines that are independent from and are shared between multiple programs. To support this, any program state that's necessary for pipeline creation should be part of the GraphicsPipelineDesc structure. This change places the state affecting fragment output in GraphicsPipelineDesc. Bug: angleproject:7369 Change-Id: I2e48fc9da220475e1b2ed376fc947ce13489610e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3963652 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Charlie Lao <cclao@google.com> Reviewed-by: Amirali Abdolrashidi <abdolrashidi@google.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
//
// 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.
//
// VulkanPipelineCachePerf:
// Performance benchmark for the Vulkan Pipeline cache.
#include "ANGLEPerfTest.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
#include "util/random_utils.h"
using namespace rx;
namespace
{
constexpr unsigned int kIterationsPerStep = 100;
struct Params
{
bool withDynamicState = false;
};
class VulkanPipelineCachePerfTest : public ANGLEPerfTest,
public ::testing::WithParamInterface<Params>
{
public:
VulkanPipelineCachePerfTest();
~VulkanPipelineCachePerfTest();
void SetUp() override;
void step() override;
GraphicsPipelineCache<GraphicsPipelineDescCompleteHash> mCache;
angle::RNG mRNG;
std::vector<vk::GraphicsPipelineDesc> mCacheHits;
std::vector<vk::GraphicsPipelineDesc> mCacheMisses;
size_t mMissIndex = 0;
private:
void randomizeDesc(vk::GraphicsPipelineDesc *desc);
};
VulkanPipelineCachePerfTest::VulkanPipelineCachePerfTest()
: ANGLEPerfTest("VulkanPipelineCachePerf", "", "", kIterationsPerStep), mRNG(0x12345678u)
{}
VulkanPipelineCachePerfTest::~VulkanPipelineCachePerfTest()
{
mCache.reset();
}
void VulkanPipelineCachePerfTest::SetUp()
{
// Insert a number of random pipeline states.
for (int pipelineCount = 0; pipelineCount < 100; ++pipelineCount)
{
vk::Pipeline pipeline;
vk::GraphicsPipelineDesc desc;
randomizeDesc(&desc);
if (pipelineCount < 10)
{
mCacheHits.push_back(desc);
}
mCache.populate(desc, std::move(pipeline));
}
for (int missCount = 0; missCount < 10000; ++missCount)
{
vk::GraphicsPipelineDesc desc;
randomizeDesc(&desc);
mCacheMisses.push_back(desc);
}
}
void VulkanPipelineCachePerfTest::randomizeDesc(vk::GraphicsPipelineDesc *desc)
{
std::vector<uint8_t> bytes(sizeof(vk::GraphicsPipelineDesc));
FillVectorWithRandomUBytes(&mRNG, &bytes);
memcpy(desc, bytes.data(), sizeof(vk::GraphicsPipelineDesc));
desc->setSupportsDynamicStateForTest(GetParam().withDynamicState);
}
void VulkanPipelineCachePerfTest::step()
{
vk::RenderPass rp;
vk::PipelineLayout pl;
vk::PipelineCache pc;
PipelineCacheAccess spc;
vk::RefCounted<vk::ShaderAndSerial> vsAndSerial;
vk::RefCounted<vk::ShaderAndSerial> fsAndSerial;
vk::ShaderAndSerialMap ssm;
const vk::GraphicsPipelineDesc *desc = nullptr;
vk::PipelineHelper *result = nullptr;
// The Vulkan handle types are difficult to cast to without #ifdefs.
VkShaderModule vs = (VkShaderModule)1;
VkShaderModule fs = (VkShaderModule)2;
vsAndSerial.get().get().setHandle(vs);
fsAndSerial.get().get().setHandle(fs);
ssm[gl::ShaderType::Vertex].set(&vsAndSerial);
ssm[gl::ShaderType::Fragment].set(&fsAndSerial);
spc.init(&pc, nullptr);
vk::SpecializationConstants defaultSpecConsts{};
for (unsigned int iteration = 0; iteration < kIterationsPerStep; ++iteration)
{
for (const auto &hit : mCacheHits)
{
(void)mCache.getPipeline(VK_NULL_HANDLE, &spc, rp, pl, ssm, defaultSpecConsts,
PipelineSource::Draw, hit, &desc, &result);
}
}
for (int missCount = 0; missCount < 20 && mMissIndex < mCacheMisses.size();
++missCount, ++mMissIndex)
{
const auto &miss = mCacheMisses[mMissIndex];
(void)mCache.getPipeline(VK_NULL_HANDLE, &spc, rp, pl, ssm, defaultSpecConsts,
PipelineSource::Draw, miss, &desc, &result);
}
vsAndSerial.get().get().setHandle(VK_NULL_HANDLE);
fsAndSerial.get().get().setHandle(VK_NULL_HANDLE);
}
} // anonymous namespace
// Test performance of pipeline hash and look up in Vulkan
TEST_P(VulkanPipelineCachePerfTest, Run)
{
run();
}
INSTANTIATE_TEST_SUITE_P(,
VulkanPipelineCachePerfTest,
::testing::ValuesIn(std::vector<Params>{{Params{false}, Params{true}}}));