Commit d34ab323 by Tim Van Patten Committed by Commit Bot

Vulkan: Save linked ProgramExecutable data

PPOs need to support drawing with Programs that failed their last linkProgram() if they had previously successfully linked. This requires saving the ProgramExecutable when linkProgram() succeeds, and not overwriting it with subsequent linkProgram() calls unil the next successful one. To achieve this, the new member ProgramState::mLinkedExecutable will point to the last successfully linked ProgramExecutable and ProgramState::mExecutable will point to a new ProgramExecutable when the next linkProgram() is attempted. If the link fails, the newly allocated ProgramExecutable will be delete()'ed and mExecutable will point to the previous 'good' ProgramExecutable still being tracked by mLinkedExecutable. If it succeeds, the old mLinkedExecutable will be delete()'ed and mLinkedExecutable will be updated to point to the ne one. Bug: angleproject:4514 Test: KHR-GLES31.core.sepshaderobjs.StateInteraction Change-Id: I0677602a6d652a055404667ec9e9305fed5b4177 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2181450 Commit-Queue: Tim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 5d01d538
...@@ -737,6 +737,7 @@ void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block) ...@@ -737,6 +737,7 @@ void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block)
// Saves the linking context for later use in resolveLink(). // Saves the linking context for later use in resolveLink().
struct Program::LinkingState struct Program::LinkingState
{ {
std::shared_ptr<ProgramExecutable> linkedExecutable;
std::unique_ptr<ProgramLinkedResources> resources; std::unique_ptr<ProgramLinkedResources> resources;
egl::BlobCache::Key programHash; egl::BlobCache::Key programHash;
std::unique_ptr<rx::LinkEvent> linkEvent; std::unique_ptr<rx::LinkEvent> linkEvent;
...@@ -1104,7 +1105,6 @@ ProgramState::ProgramState() ...@@ -1104,7 +1105,6 @@ ProgramState::ProgramState()
ProgramState::~ProgramState() ProgramState::~ProgramState()
{ {
ASSERT(!hasAttachedShader()); ASSERT(!hasAttachedShader());
SafeDelete(mExecutable);
} }
const std::string &ProgramState::getLabel() const std::string &ProgramState::getLabel()
...@@ -1408,26 +1408,40 @@ angle::Result Program::linkMergedVaryings(const Context *context, ...@@ -1408,26 +1408,40 @@ angle::Result Program::linkMergedVaryings(const Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result Program::link(const Context *context)
{
angle::Result result = linkImpl(context);
// Avoid having two ProgramExecutables if the link failed and the Program had successfully
// linked previously.
if (mLinkingState && mLinkingState->linkedExecutable)
{
mState.mExecutable = mLinkingState->linkedExecutable;
}
return result;
}
// The attached shaders are checked for linking errors by matching up their variables. // The attached shaders are checked for linking errors by matching up their variables.
// Uniform, input and output variables get collected. // Uniform, input and output variables get collected.
// The code gets compiled into binaries. // The code gets compiled into binaries.
angle::Result Program::link(const Context *context) angle::Result Program::linkImpl(const Context *context)
{ {
ASSERT(mLinkResolved); ASSERT(mLinkResolved);
// Don't make any local variables pointing to anything within the ProgramExecutable, since
// unlink() could make a new ProgramExecutable making any references/pointers invalid.
const auto &data = context->getState(); const auto &data = context->getState();
InfoLog &infoLog = mState.mExecutable->getInfoLog();
auto *platform = ANGLEPlatformCurrent(); auto *platform = ANGLEPlatformCurrent();
double startTime = platform->currentTime(platform); double startTime = platform->currentTime(platform);
// Unlink the program, but do not clear the validation-related caching yet, since we can still // Unlink the program, but do not clear the validation-related caching yet, since we can still
// use the previously linked program if linking the shaders fails // use the previously linked program if linking the shaders fails.
mLinked = false; mLinked = false;
infoLog.reset(); mState.mExecutable->getInfoLog().reset();
// Validate we have properly attached shaders before checking the cache. // Validate we have properly attached shaders before checking the cache.
if (!linkValidateShaders(infoLog)) if (!linkValidateShaders(mState.mExecutable->getInfoLog()))
{ {
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1455,6 +1469,7 @@ angle::Result Program::link(const Context *context) ...@@ -1455,6 +1469,7 @@ angle::Result Program::link(const Context *context)
// Cache load failed, fall through to normal linking. // Cache load failed, fall through to normal linking.
unlink(); unlink();
InfoLog &infoLog = mState.mExecutable->getInfoLog();
// Re-link shaders after the unlink call. // Re-link shaders after the unlink call.
bool result = linkValidateShaders(infoLog); bool result = linkValidateShaders(infoLog);
...@@ -1605,6 +1620,14 @@ angle::Result Program::link(const Context *context) ...@@ -1605,6 +1620,14 @@ angle::Result Program::link(const Context *context)
mState.updateProgramInterfaceInputs(); mState.updateProgramInterfaceInputs();
mState.updateProgramInterfaceOutputs(); mState.updateProgramInterfaceOutputs();
// Linking has succeeded, so we need to save some information that may get overwritten by a
// later linkProgram() that could fail.
if (mState.mSeparable)
{
mState.mExecutable->saveLinkedStateInfo();
mLinkingState->linkedExecutable = mState.mExecutable;
}
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1805,6 +1828,14 @@ void ProgramState::updateProgramInterfaceOutputs() ...@@ -1805,6 +1828,14 @@ void ProgramState::updateProgramInterfaceOutputs()
// Returns the program object to an unlinked state, before re-linking, or at destruction // Returns the program object to an unlinked state, before re-linking, or at destruction
void Program::unlink() void Program::unlink()
{ {
if (mLinkingState && mLinkingState->linkedExecutable)
{
// The new ProgramExecutable that we'll attempt to link with needs to start from a copy of
// the last successfully linked ProgramExecutable, so we don't lose any state information.
mState.mExecutable.reset(new ProgramExecutable(*mLinkingState->linkedExecutable));
}
mState.mExecutable->reset();
mState.mUniformLocations.clear(); mState.mUniformLocations.clear();
mState.mBufferVariables.clear(); mState.mBufferVariables.clear();
mState.mActiveUniformBlockBindings.reset(); mState.mActiveUniformBlockBindings.reset();
...@@ -1830,8 +1861,6 @@ void Program::unlink() ...@@ -1830,8 +1861,6 @@ void Program::unlink()
mValidated = false; mValidated = false;
mLinked = false; mLinked = false;
mState.mExecutable->reset();
} }
angle::Result Program::loadBinary(const Context *context, angle::Result Program::loadBinary(const Context *context,
...@@ -1839,9 +1868,9 @@ angle::Result Program::loadBinary(const Context *context, ...@@ -1839,9 +1868,9 @@ angle::Result Program::loadBinary(const Context *context,
const void *binary, const void *binary,
GLsizei length) GLsizei length)
{ {
InfoLog &infoLog = mState.mExecutable->getInfoLog();
ASSERT(mLinkResolved); ASSERT(mLinkResolved);
unlink(); unlink();
InfoLog &infoLog = mState.mExecutable->getInfoLog();
#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED #if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
return angle::Result::Continue; return angle::Result::Continue;
...@@ -3017,7 +3046,7 @@ void Program::validate(const Caps &caps) ...@@ -3017,7 +3046,7 @@ void Program::validate(const Caps &caps)
bool Program::validateSamplersImpl(InfoLog *infoLog, const Caps &caps) bool Program::validateSamplersImpl(InfoLog *infoLog, const Caps &caps)
{ {
const ProgramExecutable *executable = mState.mExecutable; const ProgramExecutable *executable = mState.mExecutable.get();
ASSERT(mLinkResolved); ASSERT(mLinkResolved);
// if any two active samplers in a program are of different types, but refer to the same // if any two active samplers in a program are of different types, but refer to the same
......
...@@ -414,7 +414,7 @@ class ProgramState final : angle::NonCopyable ...@@ -414,7 +414,7 @@ class ProgramState final : angle::NonCopyable
// uniforms in GLES3.1+. It is used to pre-set the location of uniforms. // uniforms in GLES3.1+. It is used to pre-set the location of uniforms.
ProgramAliasedBindings mUniformLocationBindings; ProgramAliasedBindings mUniformLocationBindings;
ProgramExecutable *mExecutable; std::shared_ptr<ProgramExecutable> mExecutable;
}; };
struct ProgramVaryingRef struct ProgramVaryingRef
...@@ -849,6 +849,8 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -849,6 +849,8 @@ class Program final : angle::NonCopyable, public LabeledObject
void unlink(); void unlink();
void deleteSelf(const Context *context); void deleteSelf(const Context *context);
angle::Result linkImpl(const Context *context);
bool linkValidateShaders(InfoLog &infoLog); bool linkValidateShaders(InfoLog &infoLog);
bool linkAttributes(const Context *context, InfoLog &infoLog); bool linkAttributes(const Context *context, InfoLog &infoLog);
bool linkInterfaceBlocks(const Caps &caps, bool linkInterfaceBlocks(const Caps &caps,
......
...@@ -30,8 +30,40 @@ ProgramExecutable::ProgramExecutable() ...@@ -30,8 +30,40 @@ ProgramExecutable::ProgramExecutable()
mSamplerUniformRange(0, 0), mSamplerUniformRange(0, 0),
mImageUniformRange(0, 0) mImageUniformRange(0, 0)
{ {
mActiveSamplerTypes.fill(TextureType::InvalidEnum); reset();
mActiveSamplerFormats.fill(SamplerFormat::InvalidEnum); }
ProgramExecutable::ProgramExecutable(const ProgramExecutable &other)
: mProgramState(other.mProgramState),
mProgramPipelineState(other.mProgramPipelineState),
mLinkedGraphicsShaderStages(other.mLinkedGraphicsShaderStages),
mLinkedComputeShaderStages(other.mLinkedComputeShaderStages),
mActiveAttribLocationsMask(other.mActiveAttribLocationsMask),
mMaxActiveAttribLocation(other.mMaxActiveAttribLocation),
mAttributesTypeMask(other.mAttributesTypeMask),
mAttributesMask(other.mAttributesMask),
mActiveSamplersMask(other.mActiveSamplersMask),
mActiveSamplerRefCounts(other.mActiveSamplerRefCounts),
mActiveSamplerTypes(other.mActiveSamplerTypes),
mActiveSamplerFormats(other.mActiveSamplerFormats),
mActiveSamplerShaderBits(other.mActiveSamplerShaderBits),
mActiveImagesMask(other.mActiveImagesMask),
mActiveImageShaderBits(other.mActiveImageShaderBits),
mCanDrawWith(other.mCanDrawWith),
mOutputVariables(other.mOutputVariables),
mOutputLocations(other.mOutputLocations),
mProgramInputs(other.mProgramInputs),
mLinkedTransformFeedbackVaryings(other.mLinkedTransformFeedbackVaryings),
mTransformFeedbackStrides(other.mTransformFeedbackStrides),
mTransformFeedbackBufferMode(other.mTransformFeedbackBufferMode),
mUniforms(other.mUniforms),
mSamplerUniformRange(other.mSamplerUniformRange),
mUniformBlocks(other.mUniformBlocks),
mAtomicCounterBuffers(other.mAtomicCounterBuffers),
mImageUniformRange(other.mImageUniformRange),
mShaderStorageBlocks(other.mShaderStorageBlocks)
{
reset();
} }
ProgramExecutable::~ProgramExecutable() = default; ProgramExecutable::~ProgramExecutable() = default;
...@@ -477,4 +509,19 @@ void ProgramExecutable::updateCanDrawWith() ...@@ -477,4 +509,19 @@ void ProgramExecutable::updateCanDrawWith()
(hasLinkedShaderStage(ShaderType::Vertex) && hasLinkedShaderStage(ShaderType::Fragment)); (hasLinkedShaderStage(ShaderType::Vertex) && hasLinkedShaderStage(ShaderType::Fragment));
} }
void ProgramExecutable::saveLinkedStateInfo()
{
// Only a Program's linked data needs to be saved, not a ProgramPipeline's
ASSERT(mProgramState);
for (ShaderType shaderType : getLinkedShaderStages())
{
Shader *shader = mProgramState->getAttachedShader(shaderType);
ASSERT(shader);
mLinkedOutputVaryings[shaderType] = shader->getOutputVaryings();
mLinkedInputVaryings[shaderType] = shader->getInputVaryings();
mLinkedShaderVersions[shaderType] = shader->getShaderVersion();
}
}
} // namespace gl } // namespace gl
...@@ -102,6 +102,7 @@ class ProgramExecutable ...@@ -102,6 +102,7 @@ class ProgramExecutable
{ {
public: public:
ProgramExecutable(); ProgramExecutable();
ProgramExecutable(const ProgramExecutable &other);
virtual ~ProgramExecutable(); virtual ~ProgramExecutable();
void reset(); void reset();
...@@ -273,6 +274,17 @@ class ProgramExecutable ...@@ -273,6 +274,17 @@ class ProgramExecutable
return *mResources; return *mResources;
} }
void saveLinkedStateInfo();
std::vector<sh::ShaderVariable> getLinkedOutputVaryings(ShaderType shaderType)
{
return mLinkedOutputVaryings[shaderType];
}
std::vector<sh::ShaderVariable> getLinkedInputVaryings(ShaderType shaderType)
{
return mLinkedInputVaryings[shaderType];
}
int getLinkedShaderVersion(ShaderType shaderType) { return mLinkedShaderVersions[shaderType]; }
private: private:
// TODO(timvp): http://anglebug.com/3570: Investigate removing these friend // TODO(timvp): http://anglebug.com/3570: Investigate removing these friend
// class declarations and accessing the necessary members with getters/setters. // class declarations and accessing the necessary members with getters/setters.
...@@ -343,6 +355,9 @@ class ProgramExecutable ...@@ -343,6 +355,9 @@ class ProgramExecutable
RangeUI mImageUniformRange; RangeUI mImageUniformRange;
std::vector<InterfaceBlock> mShaderStorageBlocks; std::vector<InterfaceBlock> mShaderStorageBlocks;
ShaderMap<std::vector<sh::ShaderVariable>> mLinkedOutputVaryings;
ShaderMap<std::vector<sh::ShaderVariable>> mLinkedInputVaryings;
ShaderMap<int> mLinkedShaderVersions;
// TODO: http://anglebug.com/4514: Remove // TODO: http://anglebug.com/4514: Remove
std::unique_ptr<gl::ProgramLinkedResources> mResources; std::unique_ptr<gl::ProgramLinkedResources> mResources;
}; };
......
...@@ -514,31 +514,26 @@ bool ProgramPipeline::linkVaryings(InfoLog &infoLog) const ...@@ -514,31 +514,26 @@ bool ProgramPipeline::linkVaryings(InfoLog &infoLog) const
ShaderType previousShaderType = ShaderType::InvalidEnum; ShaderType previousShaderType = ShaderType::InvalidEnum;
for (ShaderType shaderType : getExecutable().getLinkedShaderStages()) for (ShaderType shaderType : getExecutable().getLinkedShaderStages())
{ {
Program *currentProgram = mState.mPrograms[shaderType]; Program *program = getShaderProgram(shaderType);
ASSERT(currentProgram); ASSERT(program);
Shader *currentShader = ProgramExecutable &executable = program->getExecutable();
const_cast<Shader *>(currentProgram->getState().getAttachedShader(shaderType));
ASSERT(currentShader);
if (previousShaderType != ShaderType::InvalidEnum) if (previousShaderType != ShaderType::InvalidEnum)
{ {
const Program *previousProgram = mState.mPrograms[previousShaderType]; Program *previousProgram = getShaderProgram(previousShaderType);
ASSERT(previousProgram); ASSERT(previousProgram);
Shader *previousShader = const_cast<Shader *>( ProgramExecutable &previousExecutable = previousProgram->getExecutable();
previousProgram->getState().getAttachedShader(previousShaderType));
ASSERT(previousShader);
const std::vector<sh::ShaderVariable> &outputVaryings =
previousShader->getOutputVaryings();
if (!Program::linkValidateShaderInterfaceMatching( if (!Program::linkValidateShaderInterfaceMatching(
outputVaryings, currentShader->getInputVaryings(), previousShaderType, previousExecutable.getLinkedOutputVaryings(previousShaderType),
currentShader->getType(), previousShader->getShaderVersion(), executable.getLinkedInputVaryings(shaderType), previousShaderType, shaderType,
currentShader->getShaderVersion(), true, infoLog)) previousExecutable.getLinkedShaderVersion(previousShaderType),
executable.getLinkedShaderVersion(shaderType), true, infoLog))
{ {
return false; return false;
} }
} }
previousShaderType = currentShader->getType(); previousShaderType = shaderType;
} }
Program *vertexProgram = mState.mPrograms[ShaderType::Vertex]; Program *vertexProgram = mState.mPrograms[ShaderType::Vertex];
...@@ -547,15 +542,12 @@ bool ProgramPipeline::linkVaryings(InfoLog &infoLog) const ...@@ -547,15 +542,12 @@ bool ProgramPipeline::linkVaryings(InfoLog &infoLog) const
{ {
return false; return false;
} }
Shader *vertexShader = ProgramExecutable &vertexExecutable = vertexProgram->getExecutable();
const_cast<Shader *>(vertexProgram->getState().getAttachedShader(ShaderType::Vertex)); ProgramExecutable &fragmentExecutable = fragmentProgram->getExecutable();
Shader *fragmentShader = return Program::linkValidateBuiltInVaryings(
const_cast<Shader *>(fragmentProgram->getState().getAttachedShader(ShaderType::Fragment)); vertexExecutable.getLinkedOutputVaryings(ShaderType::Vertex),
ASSERT(vertexShader); fragmentExecutable.getLinkedInputVaryings(ShaderType::Fragment),
ASSERT(fragmentShader); vertexExecutable.getLinkedShaderVersion(ShaderType::Vertex), infoLog);
return Program::linkValidateBuiltInVaryings(vertexShader->getOutputVaryings(),
fragmentShader->getInputVaryings(),
vertexShader->getShaderVersion(), infoLog);
} }
void ProgramPipeline::validate(const gl::Context *context) void ProgramPipeline::validate(const gl::Context *context)
......
...@@ -3236,6 +3236,13 @@ angle::Result State::onProgramExecutableChange(const Context *context, Program * ...@@ -3236,6 +3236,13 @@ angle::Result State::onProgramExecutableChange(const Context *context, Program *
// generated executable code will be installed as part of the current rendering state." // generated executable code will be installed as part of the current rendering state."
ASSERT(program->isLinked()); ASSERT(program->isLinked());
// If this Program is currently active, we need to update the State's pointer to the current
// ProgramExecutable if we just changed it.
if (mProgram == program)
{
mExecutable = &program->getExecutable();
}
mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE); mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE);
if (program->hasAnyDirtyBit()) if (program->hasAnyDirtyBit())
......
...@@ -36,9 +36,6 @@ ...@@ -36,9 +36,6 @@
//// Failures blocking an official GLES 3.1 conformance run on SwiftShader //// Failures blocking an official GLES 3.1 conformance run on SwiftShader
//// ////
// Separate shader objects:
3570 VULKAN : KHR-GLES31.core.sepshaderobjs.StateInteraction = SKIP
// Image related failures // Image related failures
4315 VULKAN : KHR-GLES31.core.shader_image_load_store.advanced-memory-order-vsfs = FAIL 4315 VULKAN : KHR-GLES31.core.shader_image_load_store.advanced-memory-order-vsfs = FAIL
......
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