Commit 774cd1b2 by Tim Van Patten Committed by Commit Bot

Vulkan: Only transform SPIR-V once

Prior to this change, the SPIR-V would be transformed as part of GlslangGetShaderSpirvCode() and then possibly another time afterward to disable the early fragment test optmization (for monolithic programs) or to update the descriptor set/binding values (for PPOs). By storing the original SPIR-V in the ProgramVk and the transformed SPIR-V in the ProgramExecutableVk, we can now remove the SPIR-V transformation from GlslangGetShaderSpirvCode() and only perform it once in ProgramInfo::initProgram() for monolithic programs and PPOs. Bug: angleproject:4513 Test: CQ Change-Id: I4e7240b2abe7c796c46cf531948dad0e37c1419a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2267537 Commit-Queue: Tim Van Patten <timvp@google.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 8ea72e86
......@@ -875,77 +875,6 @@ constexpr gl::ShaderMap<EShLanguage> kShLanguageMap = {
{gl::ShaderType::Compute, EShLangCompute},
};
angle::Result GetShaderSpirvCode(GlslangErrorCallback callback,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *spirvBlobsOut)
{
// Enable SPIR-V and Vulkan rules when parsing GLSL
EShMessages messages = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
TBuiltInResource builtInResources(glslang::DefaultTBuiltInResource);
GetBuiltInResourcesFromCaps(glCaps, &builtInResources);
glslang::TShader vertexShader(EShLangVertex);
glslang::TShader fragmentShader(EShLangFragment);
glslang::TShader geometryShader(EShLangGeometry);
glslang::TShader computeShader(EShLangCompute);
gl::ShaderMap<glslang::TShader *> shaders = {
{gl::ShaderType::Vertex, &vertexShader},
{gl::ShaderType::Fragment, &fragmentShader},
{gl::ShaderType::Geometry, &geometryShader},
{gl::ShaderType::Compute, &computeShader},
};
glslang::TProgram program;
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
if (shaderSources[shaderType].empty())
{
continue;
}
const char *shaderString = shaderSources[shaderType].c_str();
int shaderLength = static_cast<int>(shaderSources[shaderType].size());
glslang::TShader *shader = shaders[shaderType];
shader->setStringsWithLengths(&shaderString, &shaderLength, 1);
shader->setEntryPoint("main");
bool result = shader->parse(&builtInResources, 450, ECoreProfile, false, false, messages);
if (!result)
{
ERR() << "Internal error parsing Vulkan shader corresponding to " << shaderType << ":\n"
<< shader->getInfoLog() << "\n"
<< shader->getInfoDebugLog() << "\n";
ANGLE_GLSLANG_CHECK(callback, false, GlslangError::InvalidShader);
}
program.addShader(shader);
}
bool linkResult = program.link(messages);
if (!linkResult)
{
ERR() << "Internal error linking Vulkan shaders:\n" << program.getInfoLog() << "\n";
ANGLE_GLSLANG_CHECK(callback, false, GlslangError::InvalidShader);
}
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
if (shaderSources[shaderType].empty())
{
continue;
}
glslang::TIntermediate *intermediate = program.getIntermediate(kShLanguageMap[shaderType]);
glslang::GlslangToSpv(*intermediate, (*spirvBlobsOut)[shaderType]);
}
return angle::Result::Continue;
}
void ValidateSpirvMessage(spv_message_level_t level,
const char *source,
const spv_position_t &position,
......@@ -1963,22 +1892,67 @@ angle::Result GlslangGetShaderSpirvCode(const GlslangErrorCallback &callback,
const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<SpirvBlob> *spirvBlobsOut)
{
gl::ShaderMap<SpirvBlob> initialSpirvBlobs;
ANGLE_TRY(GetShaderSpirvCode(callback, glCaps, shaderSources, &initialSpirvBlobs));
for (const gl::ShaderType shaderType : linkedShaderStages)
{
// we pass in false here to skip modifications related to early fragment tests
// optimizations and line rasterization. These are done in the initProgram time since they
// are related to context state. We must keep original untouched spriv blobs here because we
// do not have ability to add back in at initProgram time.
angle::Result status =
GlslangTransformSpirvCode(callback, shaderType, false, variableInfoMap[shaderType],
initialSpirvBlobs[shaderType], &(*spirvBlobsOut)[shaderType]);
if (status != angle::Result::Continue)
// Enable SPIR-V and Vulkan rules when parsing GLSL
EShMessages messages = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
TBuiltInResource builtInResources(glslang::DefaultTBuiltInResource);
GetBuiltInResourcesFromCaps(glCaps, &builtInResources);
glslang::TShader vertexShader(EShLangVertex);
glslang::TShader fragmentShader(EShLangFragment);
glslang::TShader geometryShader(EShLangGeometry);
glslang::TShader computeShader(EShLangCompute);
gl::ShaderMap<glslang::TShader *> shaders = {
{gl::ShaderType::Vertex, &vertexShader},
{gl::ShaderType::Fragment, &fragmentShader},
{gl::ShaderType::Geometry, &geometryShader},
{gl::ShaderType::Compute, &computeShader},
};
glslang::TProgram program;
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
if (shaderSources[shaderType].empty())
{
return status;
continue;
}
const char *shaderString = shaderSources[shaderType].c_str();
int shaderLength = static_cast<int>(shaderSources[shaderType].size());
glslang::TShader *shader = shaders[shaderType];
shader->setStringsWithLengths(&shaderString, &shaderLength, 1);
shader->setEntryPoint("main");
bool result = shader->parse(&builtInResources, 450, ECoreProfile, false, false, messages);
if (!result)
{
ERR() << "Internal error parsing Vulkan shader corresponding to " << shaderType << ":\n"
<< shader->getInfoLog() << "\n"
<< shader->getInfoDebugLog() << "\n";
ANGLE_GLSLANG_CHECK(callback, false, GlslangError::InvalidShader);
}
program.addShader(shader);
}
bool linkResult = program.link(messages);
if (!linkResult)
{
ERR() << "Internal error linking Vulkan shaders:\n" << program.getInfoLog() << "\n";
ANGLE_GLSLANG_CHECK(callback, false, GlslangError::InvalidShader);
}
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
if (shaderSources[shaderType].empty())
{
continue;
}
glslang::TIntermediate *intermediate = program.getIntermediate(kShLanguageMap[shaderType]);
glslang::GlslangToSpv(*intermediate, (*spirvBlobsOut)[shaderType]);
}
return angle::Result::Continue;
......
......@@ -242,9 +242,29 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{
return rx::GlslangGetShaderSpirvCode(
gl::ShaderMap<SpirvBlob> initialSpirvBlobs;
ANGLE_TRY(rx::GlslangGetShaderSpirvCode(
[context](GlslangError error) { return HandleError(context, error); }, linkedShaderStages,
glCaps, shaderSources, variableInfoMap, shaderCodeOut);
glCaps, shaderSources, variableInfoMap, &initialSpirvBlobs));
for (const gl::ShaderType shaderType : linkedShaderStages)
{
// we pass in false here to skip modifications related to early fragment tests
// optimizations and line rasterization. These are done in the initProgram time since they
// are related to context state. We must keep original untouched spriv blobs here because we
// do not have ability to add back in at initProgram time.
angle::Result status = GlslangTransformSpirvCode(
[context](GlslangError error) { return HandleError(context, error); }, shaderType,
false, variableInfoMap[shaderType], initialSpirvBlobs[shaderType],
&(*shaderCodeOut)[shaderType]);
if (status != angle::Result::Continue)
{
return status;
}
}
return angle::Result::Continue;
}
angle::Result SpirvCodeToMsl(Context *context,
......
......@@ -116,44 +116,30 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
ProgramTransformOptionBits optionBits,
ProgramExecutableVk *executableVk)
{
const ShaderMapInterfaceVariableInfoMap &variableInfoMap =
executableVk->getShaderInterfaceVariableInfoMap();
const gl::ShaderMap<SpirvBlob> &originalSpirvBlobs = shaderInfo.getSpirvBlobs();
const SpirvBlob &originalSpirvBlob = originalSpirvBlobs[shaderType];
const gl::ShaderMap<SpirvBlob> &transformedSpirvBlobs =
executableVk->getTransformedShaderInfo().getSpirvBlobs();
const SpirvBlob &transformedSpirvBlob = transformedSpirvBlobs[shaderType];
if (!transformedSpirvBlob.empty())
if (executableVk->getTransformedShaderInfo().getSpirvBlobs()[shaderType].empty())
{
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(),
transformedSpirvBlob.data(),
transformedSpirvBlob.size() * sizeof(uint32_t)));
}
else
{
if (shaderType == gl::ShaderType::Fragment &&
optionBits[ProgramTransformOption::RemoveEarlyFragmentTestsOptimization])
{
SpirvBlob &spirvBlobTransformed =
executableVk->getTransformedShaderInfo().getSpirvBlobs()[shaderType];
ANGLE_TRY(GlslangWrapperVk::TransformSpirV(contextVk, shaderType, true,
variableInfoMap[shaderType],
originalSpirvBlob, &spirvBlobTransformed));
const ShaderMapInterfaceVariableInfoMap &variableInfoMap =
executableVk->getShaderInterfaceVariableInfoMap();
const gl::ShaderMap<SpirvBlob> &originalSpirvBlobs = shaderInfo.getSpirvBlobs();
const SpirvBlob &originalSpirvBlob = originalSpirvBlobs[shaderType];
bool removeEarlyFragmentTestsOptimization =
(shaderType == gl::ShaderType::Fragment &&
optionBits[ProgramTransformOption::RemoveEarlyFragmentTestsOptimization]);
SpirvBlob &spirvBlobTransformed =
executableVk->getTransformedShaderInfo().getSpirvBlobs()[shaderType];
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(),
spirvBlobTransformed.data(),
spirvBlobTransformed.size() * sizeof(uint32_t)));
}
else
{
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(),
originalSpirvBlob.data(),
originalSpirvBlob.size() * sizeof(uint32_t)));
}
ANGLE_TRY(GlslangWrapperVk::TransformSpirV(
contextVk, shaderType, removeEarlyFragmentTestsOptimization,
variableInfoMap[shaderType], originalSpirvBlob, &spirvBlobTransformed));
}
const gl::ShaderMap<SpirvBlob> &transformedSpirvBlobs =
executableVk->getTransformedShaderInfo().getSpirvBlobs();
const SpirvBlob &transformedSpirvBlob = transformedSpirvBlobs[shaderType];
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(),
transformedSpirvBlob.data(),
transformedSpirvBlob.size() * sizeof(uint32_t)));
mProgramHelper.setShader(shaderType, &mShaders[shaderType]);
if (optionBits[ProgramTransformOption::EnableLineRasterEmulation])
......
......@@ -89,39 +89,9 @@ angle::Result ProgramPipelineVk::link(const gl::Context *glContext)
}
}
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];
SpirvBlob &transformedSpirvBlob =
mExecutable.getTransformedShaderInfo().getSpirvBlobs()[shaderType];
ASSERT(transformedSpirvBlob.empty());
// 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->getOriginalShaderInfo().getSpirvBlobs()[shaderType],
&transformedSpirvBlob));
}
}
return angle::Result::Continue;
}
angle::Result ProgramPipelineVk::updateUniforms(ContextVk *contextVk)
{
uint32_t offsetIndex = 0;
......
......@@ -47,8 +47,6 @@ class ProgramPipelineVk : public ProgramPipelineImpl
angle::Result link(const gl::Context *context) override;
angle::Result transformShaderSpirV(const gl::Context *glContext);
angle::Result updateUniforms(ContextVk *contextVk);
bool dirtyUniforms(const gl::State &glState);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment