| // |
| // 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) |
| { |
| mExecutable.setProgramPipeline(this); |
| } |
| |
| ProgramPipelineVk::~ProgramPipelineVk() {} |
| |
| void ProgramPipelineVk::destroy(const gl::Context *context) |
| { |
| ContextVk *contextVk = vk::GetImpl(context); |
| reset(contextVk); |
| } |
| |
| void ProgramPipelineVk::reset(ContextVk *contextVk) |
| { |
| mExecutable.reset(contextVk); |
| } |
| |
| // TODO: http://anglebug.com/3570: Move/Copy all of the necessary information into |
| // the ProgramExecutable, so this function can be removed. |
| void ProgramPipelineVk::fillProgramStateMap( |
| const ContextVk *contextVk, |
| gl::ShaderMap<const gl::ProgramState *> *programStatesOut) |
| { |
| for (gl::ShaderType shaderType : gl::AllShaderTypes()) |
| { |
| (*programStatesOut)[shaderType] = nullptr; |
| |
| ProgramVk *programVk = getShaderProgram(contextVk->getState(), shaderType); |
| if (programVk) |
| { |
| (*programStatesOut)[shaderType] = &programVk->getState(); |
| } |
| } |
| } |
| |
| angle::Result ProgramPipelineVk::link(const gl::Context *glContext) |
| { |
| ContextVk *contextVk = vk::GetImpl(glContext); |
| const gl::State &glState = glContext->getState(); |
| const gl::ProgramPipeline *glPipeline = glState.getProgramPipeline(); |
| GlslangSourceOptions options = |
| GlslangWrapperVk::CreateSourceOptions(contextVk->getRenderer()->getFeatures()); |
| GlslangProgramInterfaceInfo glslangProgramInterfaceInfo; |
| GlslangWrapperVk::ResetGlslangProgramInterfaceInfo(&glslangProgramInterfaceInfo); |
| |
| 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. |
| for (const gl::ShaderType shaderType : glPipeline->getExecutable().getLinkedShaderStages()) |
| { |
| gl::Program *glProgram = |
| const_cast<gl::Program *>(glPipeline->getShaderProgram(shaderType)); |
| if (glProgram) |
| { |
| // The program interface info must survive across shaders, except |
| // for some program-specific values. |
| ProgramVk *programVk = vk::GetImpl(glProgram); |
| GlslangProgramInterfaceInfo &programProgramInterfaceInfo = |
| programVk->getGlslangProgramInterfaceInfo(); |
| glslangProgramInterfaceInfo.locationsUsedForXfbExtension = |
| programProgramInterfaceInfo.locationsUsedForXfbExtension; |
| |
| GlslangAssignLocations(options, glProgram->getState().getExecutable(), shaderType, |
| &glslangProgramInterfaceInfo, |
| &mExecutable.getShaderInterfaceVariableInfoMap()); |
| } |
| } |
| |
| return mExecutable.createPipelineLayout(glContext); |
| } |
| |
| angle::Result ProgramPipelineVk::updateUniforms(ContextVk *contextVk) |
| { |
| uint32_t offsetIndex = 0; |
| bool anyNewBufferAllocated = false; |
| const gl::ProgramExecutable *glExecutable = contextVk->getState().getProgramExecutable(); |
| |
| for (const gl::ShaderType shaderType : glExecutable->getLinkedShaderStages()) |
| { |
| ProgramVk *programVk = getShaderProgram(contextVk->getState(), shaderType); |
| if (programVk && programVk->dirtyUniforms()) |
| { |
| ANGLE_TRY(programVk->updateShaderUniforms( |
| contextVk, shaderType, &mExecutable.mDynamicBufferOffsets[offsetIndex], |
| &anyNewBufferAllocated)); |
| } |
| ++offsetIndex; |
| } |
| |
| // The PPO's list of descriptor sets being empty without a new buffer being allocated indicates |
| // a Program that was already used in a draw command (and thus already allocated uniform |
| // buffers) has been bound to this PPO. |
| if (anyNewBufferAllocated || mExecutable.mDescriptorSets.empty()) |
| { |
| // We need to reinitialize the descriptor sets if we newly allocated buffers since we can't |
| // modify the descriptor sets once initialized. |
| ANGLE_TRY(mExecutable.allocateDescriptorSet(contextVk, kUniformsAndXfbDescriptorSetIndex)); |
| |
| mExecutable.mDescriptorBuffersCache.clear(); |
| for (const gl::ShaderType shaderType : glExecutable->getLinkedShaderStages()) |
| { |
| ProgramVk *programVk = getShaderProgram(contextVk->getState(), shaderType); |
| if (programVk) |
| { |
| mExecutable.updateDefaultUniformsDescriptorSet( |
| shaderType, programVk->getDefaultUniformBlocks(), contextVk); |
| mExecutable.updateTransformFeedbackDescriptorSetImpl(programVk->getState(), |
| contextVk); |
| } |
| } |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| bool ProgramPipelineVk::dirtyUniforms(const gl::State &glState) |
| { |
| for (const gl::ShaderType shaderType : gl::AllShaderTypes()) |
| { |
| const ProgramVk *program = getShaderProgram(glState, shaderType); |
| if (program && program->dirtyUniforms()) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| } // namespace rx |