Hash :
3680a5dc
Author :
Date :
2023-11-17T13:51:07
Vulkan: Let program warmup continue passed link The warmup task does not actually affect the link results, so there is no reason to wait for it when the application queries the link status. This change allows the warm up task to continue in parallel until the program is used at draw time. This allows the warm up to be more efficient when the link itself is not parallelized. For applications that create programs in the middle of every frame, it's still likely best to disable warm up (as the following immediate draw will already effectively do the warm up). Note that currently the warm up code in the Vulkan backend is not completely thread-safe, and so the program still blocks on that task before the first draw can happen (or the program is modified in any way). Bug: angleproject:8417 Change-Id: I0877fef39a0585c3279e32699ce817d4643d7cd6 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5037538 Reviewed-by: Charlie Lao <cclao@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Geoff Lang <geofflang@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 116 117 118 119 120 121 122 123
//
// 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"
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)
{
getExecutable()->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();
ProgramExecutableVk *executableVk = vk::GetImpl(&glExecutable);
SpvSourceOptions options = SpvCreateSourceOptions(contextVk->getFeatures());
SpvProgramInterfaceInfo spvProgramInterfaceInfo = {};
reset(contextVk);
executableVk->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::SharedProgramExecutable &glShaderExecutable =
mState.getShaderProgramExecutable(shaderType);
if (glShaderExecutable && gl::ShaderTypeSupportsTransformFeedback(shaderType))
{
const bool isTransformFeedbackStage =
shaderType == linkedTransformFeedbackStage &&
!glShaderExecutable->getLinkedTransformFeedbackVaryings().empty();
SpvAssignTransformFeedbackLocations(
shaderType, *glShaderExecutable.get(), isTransformFeedbackStage,
&spvProgramInterfaceInfo, &executableVk->mVariableInfoMap);
}
}
}
executableVk->mOriginalShaderInfo.clear();
SpvAssignLocations(options, glExecutable, varyingPacking, linkedTransformFeedbackStage,
&spvProgramInterfaceInfo, &executableVk->mVariableInfoMap);
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
const gl::SharedProgramExecutable &glShaderExecutable =
mState.getShaderProgramExecutable(shaderType);
ProgramExecutableVk *programExecutableVk = vk::GetImpl(glShaderExecutable.get());
executableVk->mDefaultUniformBlocks[shaderType] =
programExecutableVk->getSharedDefaultUniformBlock(shaderType);
executableVk->mOriginalShaderInfo.initShaderFromProgram(
shaderType, programExecutableVk->mOriginalShaderInfo);
}
executableVk->setAllDefaultUniformsDirty();
if (contextVk->getFeatures().varyingsRequireMatchingPrecisionInSpirv.enabled &&
contextVk->getFeatures().enablePrecisionQualifiers.enabled)
{
executableVk->resolvePrecisionMismatch(mergedVaryings);
}
executableVk->resetLayout(contextVk);
ANGLE_TRY(executableVk->createPipelineLayout(contextVk, &contextVk->getPipelineLayoutCache(),
&contextVk->getDescriptorSetLayoutCache(),
nullptr));
ANGLE_TRY(executableVk->initializeDescriptorPools(contextVk,
&contextVk->getDescriptorSetLayoutCache(),
&contextVk->getMetaDescriptorPools()));
angle::Result result = angle::Result::Continue;
if (contextVk->getFeatures().warmUpPipelineCacheAtLink.enabled)
{
vk::RenderPass temporaryCompatibleRenderPass;
result = executableVk->warmUpPipelineCache(contextVk, contextVk->pipelineRobustness(),
contextVk->pipelineProtectedAccess(),
&temporaryCompatibleRenderPass);
temporaryCompatibleRenderPass.destroy(contextVk->getDevice());
}
return result;
} // namespace rx
void ProgramPipelineVk::onProgramUniformUpdate(gl::ShaderType shaderType)
{
getExecutable()->mDefaultUniformBlocksDirty.set(shaderType);
}
} // namespace rx