blob: 5982570954482aeddc04ceb8ca64a2785ab16b03 [file] [log] [blame] [edit]
//
// 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(), glProgram->getResources(),
shaderType, &glslangProgramInterfaceInfo,
&mExecutable.getShaderInterfaceVariableInfoMap());
}
}
ANGLE_TRY(transformShaderSpirV(glContext));
return mExecutable.createPipelineLayout(glContext);
}
angle::Result ProgramPipelineVk::transformShaderSpirV(const gl::Context *glContext)
{
ContextVk *contextVk = vk::GetImpl(glContext);
const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
ASSERT(executable);
for (const gl::ShaderType shaderType : executable->getLinkedShaderStages())
{
ProgramVk *programVk = getShaderProgram(contextVk->getState(), shaderType);
if (programVk)
{
ShaderInterfaceVariableInfoMap &variableInfoMap =
mExecutable.mVariableInfoMap[shaderType];
std::vector<uint32_t> transformedSpirvBlob;
// We skip early fragment tests optimization modification here since we need to keep
// original spriv blob here.
ANGLE_TRY(GlslangWrapperVk::TransformSpirV(
contextVk, shaderType, false, variableInfoMap,
programVk->getShaderInfo().getSpirvBlobs()[shaderType], &transformedSpirvBlob));
// Save the newly transformed SPIR-V
// TODO: http://anglebug.com/4513: Keep the original SPIR-V and
// translated SPIR-V in separate buffers in ShaderInfo to avoid the
// extra copy here.
programVk->getShaderInfo().getSpirvBlobs()[shaderType] = transformedSpirvBlob;
}
}
return angle::Result::Continue;
}
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;
}
if (anyNewBufferAllocated)
{
// 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