Hash :
97a6e581
Author :
Date :
2022-05-30T16:50:26
Vulkan: Useful implementation of program binaries ANGLE already serializes the pipeline state for the sake of OES_get_program_binary. This serialization had limited usefulness however, since the Vulkan driver hasn't actually created any pipelines yet (which is a costly part of program creation). Simultaneously, ANGLE deferred Vulkan pipeline creation to draw time, which causes hitching. In this change, a handful of Vulkan pipelines are precreated at link time; those at least that are sure to create different blobs in the pipeline cache (different spec consts or SPIR-V generation). These pipelines are created in the program executable's cache. The cache is then merged into the shared renderer cache (for potential blob reuse by other programs). With this, two goals are achieved: - Most pipelines created at draw time hit the pipeline cache, avoiding costly compilation. - When the program binary is retrieved, the contents of the program executable's pipeline cache is also returned. On reload, the cache is recovered, resulting in faster startup. Bug: angleproject:5881 Change-Id: I46c5451a7d0b16dffd40e44015e094640886880b Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3671977 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Charlie Lao <cclao@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
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
//
// Copyright 2017 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.
//
// ProgramPipelineVk.cpp:
// Implements the class methods for ProgramPipelineVk.
//
#include "libANGLE/renderer/vulkan/ProgramPipelineVk.h"
#include "libANGLE/renderer/glslang_wrapper_utils.h"
#include "libANGLE/renderer/vulkan/GlslangWrapperVk.h"
namespace rx
{
ProgramPipelineVk::ProgramPipelineVk(const gl::ProgramPipelineState &state)
: ProgramPipelineImpl(state)
{}
ProgramPipelineVk::~ProgramPipelineVk() {}
void ProgramPipelineVk::destroy(const gl::Context *context)
{
ContextVk *contextVk = vk::GetImpl(context);
reset(contextVk);
}
void ProgramPipelineVk::reset(ContextVk *contextVk)
{
mExecutable.reset(contextVk);
}
angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
const gl::ProgramMergedVaryings &mergedVaryings,
const gl::ProgramVaryingPacking &varyingPacking)
{
ContextVk *contextVk = vk::GetImpl(glContext);
const gl::ProgramExecutable &glExecutable = mState.getExecutable();
GlslangSourceOptions options =
GlslangWrapperVk::CreateSourceOptions(contextVk->getRenderer()->getFeatures());
GlslangProgramInterfaceInfo glslangProgramInterfaceInfo;
GlslangWrapperVk::ResetGlslangProgramInterfaceInfo(&glslangProgramInterfaceInfo);
reset(contextVk);
mExecutable.clearVariableInfoMap();
// Now that the program pipeline has all of the programs attached, the various descriptor
// set/binding locations need to be re-assigned to their correct values.
const gl::ShaderType linkedTransformFeedbackStage =
glExecutable.getLinkedTransformFeedbackStage();
// This should be done before assigning varying locations. Otherwise, we can encounter shader
// interface mismatching problems when the transform feedback stage is not the vertex stage.
if (options.supportsTransformFeedbackExtension)
{
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
const gl::Program *glProgram = mState.getShaderProgram(shaderType);
if (glProgram && gl::ShaderTypeSupportsTransformFeedback(shaderType))
{
const bool isTransformFeedbackStage =
shaderType == linkedTransformFeedbackStage &&
!glProgram->getState().getLinkedTransformFeedbackVaryings().empty();
GlslangAssignTransformFeedbackLocations(
shaderType, glProgram->getExecutable(), isTransformFeedbackStage,
&glslangProgramInterfaceInfo, &mExecutable.mVariableInfoMap);
}
}
}
mExecutable.mOriginalShaderInfo.clear();
gl::ShaderType frontShaderType = gl::ShaderType::InvalidEnum;
UniformBindingIndexMap uniformBindingIndexMap;
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
const bool isTransformFeedbackStage =
shaderType == linkedTransformFeedbackStage &&
!glExecutable.getLinkedTransformFeedbackVaryings().empty();
GlslangAssignLocations(options, glExecutable, varyingPacking, shaderType, frontShaderType,
isTransformFeedbackStage, &glslangProgramInterfaceInfo,
&uniformBindingIndexMap, &mExecutable.mVariableInfoMap);
frontShaderType = shaderType;
const gl::Program *program = mState.getShaderProgram(shaderType);
ProgramVk *programVk = vk::GetImpl(program);
ProgramExecutableVk &programExecutableVk = programVk->getExecutable();
mExecutable.mDefaultUniformBlocks[shaderType] =
programExecutableVk.getSharedDefaultUniformBlock(shaderType);
mExecutable.mOriginalShaderInfo.initShaderFromProgram(
shaderType, programExecutableVk.mOriginalShaderInfo);
}
mExecutable.setAllDefaultUniformsDirty(glExecutable);
if (contextVk->getFeatures().enablePrecisionQualifiers.enabled)
{
mExecutable.resolvePrecisionMismatch(mergedVaryings);
}
ANGLE_TRY(mExecutable.createPipelineLayout(contextVk, mState.getExecutable(), nullptr));
return mExecutable.warmUpPipelineCache(contextVk, mState.getExecutable());
} // namespace rx
void ProgramPipelineVk::onProgramUniformUpdate(gl::ShaderType shaderType)
{
mExecutable.mDefaultUniformBlocksDirty.set(shaderType);
}
} // namespace rx