// // 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) { 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(); SpvSourceOptions options = SpvCreateSourceOptions(contextVk->getFeatures()); SpvProgramInterfaceInfo spvProgramInterfaceInfo; spvProgramInterfaceInfo = {}; 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(); SpvAssignTransformFeedbackLocations( shaderType, glProgram->getExecutable(), isTransformFeedbackStage, &spvProgramInterfaceInfo, &mExecutable.mVariableInfoMap); } } } mExecutable.mOriginalShaderInfo.clear(); SpvAssignLocations(options, glExecutable, varyingPacking, linkedTransformFeedbackStage, &spvProgramInterfaceInfo, &mExecutable.mVariableInfoMap); for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages()) { 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().varyingsRequireMatchingPrecisionInSpirv.enabled && contextVk->getFeatures().enablePrecisionQualifiers.enabled) { mExecutable.resolvePrecisionMismatch(mergedVaryings); } ANGLE_TRY(mExecutable.createPipelineLayout(contextVk, mState.getExecutable(), nullptr)); return mExecutable.warmUpPipelineCache(contextVk, mState.getExecutable()); } // namespace rx angle::Result ProgramPipelineVk::syncState(const gl::Context *context, const gl::Program::DirtyBits &dirtyBits) { ASSERT(dirtyBits.any()); // Push dirty bits to executable so that they can be used later. mExecutable.mDirtyBits |= dirtyBits; return angle::Result::Continue; } void ProgramPipelineVk::onProgramUniformUpdate(gl::ShaderType shaderType) { mExecutable.mDefaultUniformBlocksDirty.set(shaderType); } } // namespace rx