Hash :
4a2446c6
Author :
Date :
2021-10-19T11:55:17
Vulkan: Implement robust shader outputs. In this CL we change ANGLE to pass the mask of missing shader outputs down to pipeline creation. We then use the color mask bits to block SwiftShader writing to unused outputs. This fixes the undefined behaviour present in Genshin Impact. Note that the other GLES implementations we tested don't seem to modify outputs even if they're unused. It was easier to mask out the color attachments in initialize rather than set up the pipeline desc to mask out the attachments. This was because we manipulate the color mask in a fairly complex way before we initialize the pipeline desc. Bug: angleproject:6566 Change-Id: Ie659fcd511cd286fa573fd25e3e6a0b9e123ebd6 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3232435 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Tim Van Patten <timvp@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
//
// 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/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;
class VulkanPipelineCachePerfTest : public ANGLEPerfTest
{
public:
VulkanPipelineCachePerfTest();
~VulkanPipelineCachePerfTest();
void SetUp() override;
void step() override;
GraphicsPipelineCache 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)
{}
VulkanPipelineCachePerfTest::~VulkanPipelineCachePerfTest()
{
mCache.destroy(VK_NULL_HANDLE);
}
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));
}
void VulkanPipelineCachePerfTest::step()
{
vk::RenderPass rp;
vk::PipelineLayout pl;
vk::PipelineCache pc;
vk::ShaderAndSerialMap ssm;
const vk::GraphicsPipelineDesc *desc = nullptr;
vk::PipelineHelper *result = nullptr;
gl::AttributesMask am;
gl::ComponentTypeMask ctm;
gl::DrawBufferMask dbm;
// The Vulkan handle types are difficult to cast to without #ifdefs.
VkShaderModule vs = (VkShaderModule)1;
VkShaderModule fs = (VkShaderModule)2;
ssm[gl::ShaderType::Vertex].get().get().setHandle(vs);
ssm[gl::ShaderType::Fragment].get().get().setHandle(fs);
vk::SpecializationConstants defaultSpecConsts{};
for (unsigned int iteration = 0; iteration < kIterationsPerStep; ++iteration)
{
for (const auto &hit : mCacheHits)
{
(void)mCache.getPipeline(VK_NULL_HANDLE, pc, rp, pl, am, ctm, dbm, ssm,
defaultSpecConsts, 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, pc, rp, pl, am, ctm, dbm, ssm, defaultSpecConsts,
miss, &desc, &result);
}
}
} // anonymous namespace
TEST_F(VulkanPipelineCachePerfTest, Run)
{
run();
}