mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-03 14:09:33 +03:00
Prevent shaders from recompiling while a link job is in progress
This will prevent a guarantee that link jobs can take further advantage of. In particular, a good chunk of the link job is done serially and under the share group lock due to this recompile-while-link issue. After this change, that is no longer a problem, and most of the link can be made lockless/parallelized. Bug: angleproject:8297 Change-Id: Ic41ac62fb8c40131a69cd90fa9430584964677fa Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4776338 Reviewed-by: Charlie Lao <cclao@google.com> Reviewed-by: Geoff Lang <geofflang@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
committed by
Angle LUCI CQ
parent
f9e3f67430
commit
424f43e40e
@@ -1121,13 +1121,25 @@ void Program::bindFragmentOutputIndex(GLuint index, const char *name)
|
||||
|
||||
angle::Result Program::link(const Context *context)
|
||||
{
|
||||
// Lock the shaders before linking, to prevent them from being modified during a following
|
||||
// recompile
|
||||
ScopedShaderLinkLocks shaderLocks;
|
||||
for (ShaderType shaderType : angle::AllEnums<ShaderType>())
|
||||
{
|
||||
gl::Shader *shader = mState.mAttachedShaders[shaderType];
|
||||
if (shader)
|
||||
{
|
||||
shaderLocks[shaderType] = shader->lockAndGetScopedShaderLinkLock();
|
||||
}
|
||||
}
|
||||
|
||||
const angle::FrontendFeatures &frontendFeatures = context->getFrontendFeatures();
|
||||
if (frontendFeatures.dumpShaderSource.enabled)
|
||||
{
|
||||
dumpProgramInfo();
|
||||
}
|
||||
|
||||
angle::Result result = linkImpl(context);
|
||||
angle::Result result = linkImpl(context, &shaderLocks);
|
||||
|
||||
// Avoid having two ProgramExecutables if the link failed and the Program had successfully
|
||||
// linked previously.
|
||||
@@ -1142,7 +1154,7 @@ angle::Result Program::link(const Context *context)
|
||||
// The attached shaders are checked for linking errors by matching up their variables.
|
||||
// Uniform, input and output variables get collected.
|
||||
// The code gets compiled into binaries.
|
||||
angle::Result Program::linkImpl(const Context *context)
|
||||
angle::Result Program::linkImpl(const Context *context, ScopedShaderLinkLocks *shaderLocks)
|
||||
{
|
||||
ASSERT(!mLinkingState);
|
||||
// Don't make any local variables pointing to anything within the ProgramExecutable, since
|
||||
@@ -1315,7 +1327,8 @@ angle::Result Program::linkImpl(const Context *context)
|
||||
mLinkingState = std::move(linkingState);
|
||||
mLinkingState->linkingFromBinary = false;
|
||||
mLinkingState->programHash = programHash;
|
||||
mLinkingState->linkEvent = mProgram->link(context, resources, infoLog, mergedVaryings);
|
||||
mLinkingState->linkEvent =
|
||||
mProgram->link(context, resources, infoLog, mergedVaryings, shaderLocks);
|
||||
|
||||
// Must be after mProgram->link() to avoid misleading the linker about output variables.
|
||||
mState.updateProgramInterfaceInputs(context);
|
||||
|
||||
@@ -818,7 +818,7 @@ class Program final : public LabeledObject, public angle::Subject
|
||||
void unlink();
|
||||
void deleteSelf(const Context *context);
|
||||
|
||||
angle::Result linkImpl(const Context *context);
|
||||
angle::Result linkImpl(const Context *context, ScopedShaderLinkLocks *shaderLocks);
|
||||
|
||||
bool linkValidateShaders(const Context *context, InfoLog &infoLog);
|
||||
bool linkAttributes(const Context *context, InfoLog &infoLog);
|
||||
|
||||
@@ -152,6 +152,10 @@ Shader::Shader(ShaderProgramManager *manager,
|
||||
|
||||
void Shader::onDestroy(const gl::Context *context)
|
||||
{
|
||||
// There cannot be any link jobs using this shader. Because that means the shader must be
|
||||
// attached to a program, and ref counting prevents it from being destroyed.
|
||||
ASSERT(mLinkJobsInProgress == 0);
|
||||
|
||||
resolveCompile(context);
|
||||
mImplementation->destroy();
|
||||
mBoundCompiler.set(context, nullptr);
|
||||
@@ -391,6 +395,9 @@ void Shader::compile(const Context *context)
|
||||
{
|
||||
resolveCompile(context);
|
||||
|
||||
// Do not modify the compiled state while there are link jobs in progress.
|
||||
waitForLinkJobs();
|
||||
|
||||
mState.mCompiledShaderState.translatedSource.clear();
|
||||
mState.mCompiledShaderState.compiledBinary.clear();
|
||||
mInfoLog.clear();
|
||||
@@ -1000,4 +1007,20 @@ void Shader::setShaderKey(const Context *context,
|
||||
angle::base::SHA1HashBytes(shaderKey.data(), shaderKey.size(), mShaderHash.data());
|
||||
}
|
||||
|
||||
void Shader::waitForLinkJobs()
|
||||
{
|
||||
// No known application recompiles shaders right after linking programs. This case is thus
|
||||
// purely for conformance, and performance is irrelevant.
|
||||
//
|
||||
// Wait until there are no pending link jobs.
|
||||
while (mLinkJobsInProgress > 0)
|
||||
{
|
||||
WARN() << "Detected shader recompilation while a link job is in progress. This is "
|
||||
"inefficient, do not reuse shaders.";
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(1));
|
||||
}
|
||||
|
||||
// There cannot be more link jobs added in the meantime, because of the share group lock.
|
||||
ASSERT(mLinkJobsInProgress == 0);
|
||||
}
|
||||
} // namespace gl
|
||||
|
||||
@@ -62,6 +62,30 @@ enum class CompileStatus
|
||||
COMPILED,
|
||||
};
|
||||
|
||||
class [[nodiscard]] ScopedShaderLinkLock : angle::NonCopyable
|
||||
{
|
||||
public:
|
||||
ScopedShaderLinkLock() : mShader(nullptr) {}
|
||||
ScopedShaderLinkLock(Shader *shader);
|
||||
~ScopedShaderLinkLock();
|
||||
|
||||
void swap(ScopedShaderLinkLock &other) { std::swap(mShader, other.mShader); }
|
||||
ScopedShaderLinkLock(ScopedShaderLinkLock &&other)
|
||||
{
|
||||
mShader = other.mShader;
|
||||
other.mShader = nullptr;
|
||||
}
|
||||
ScopedShaderLinkLock &operator=(ScopedShaderLinkLock &&other)
|
||||
{
|
||||
std::swap(mShader, other.mShader);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
Shader *mShader;
|
||||
};
|
||||
using ScopedShaderLinkLocks = gl::ShaderMap<ScopedShaderLinkLock>;
|
||||
|
||||
class ShaderState final : angle::NonCopyable
|
||||
{
|
||||
public:
|
||||
@@ -288,6 +312,15 @@ class Shader final : angle::NonCopyable, public LabeledObject
|
||||
return;
|
||||
}
|
||||
|
||||
void onProgramLinkBegin() { ++mLinkJobsInProgress; }
|
||||
void onProgramLinkEnd()
|
||||
{
|
||||
ASSERT(mLinkJobsInProgress > 0);
|
||||
--mLinkJobsInProgress;
|
||||
ASSERT(mLinkJobsInProgress >= 0);
|
||||
}
|
||||
ScopedShaderLinkLock lockAndGetScopedShaderLinkLock() { return ScopedShaderLinkLock(this); }
|
||||
|
||||
private:
|
||||
struct CompilingState;
|
||||
|
||||
@@ -310,6 +343,8 @@ class Shader final : angle::NonCopyable, public LabeledObject
|
||||
const ShShaderOutput &outputType,
|
||||
const ShBuiltInResources &resources);
|
||||
|
||||
void waitForLinkJobs();
|
||||
|
||||
ShaderState mState;
|
||||
std::unique_ptr<rx::ShaderImpl> mImplementation;
|
||||
const gl::Limitations mRendererLimitations;
|
||||
@@ -328,8 +363,25 @@ class Shader final : angle::NonCopyable, public LabeledObject
|
||||
|
||||
GLuint mCurrentMaxComputeWorkGroupInvocations;
|
||||
unsigned int mMaxComputeSharedMemory;
|
||||
|
||||
// Number of programs that are currently linking using this shader. If the shader is
|
||||
// recompiled, it will block until all existing link jobs are finished.
|
||||
std::atomic_int mLinkJobsInProgress;
|
||||
};
|
||||
|
||||
inline ScopedShaderLinkLock::ScopedShaderLinkLock(Shader *shader) : mShader(shader)
|
||||
{
|
||||
ASSERT(shader != nullptr);
|
||||
mShader->onProgramLinkBegin();
|
||||
}
|
||||
inline ScopedShaderLinkLock::~ScopedShaderLinkLock()
|
||||
{
|
||||
if (mShader != nullptr)
|
||||
{
|
||||
mShader->onProgramLinkEnd();
|
||||
}
|
||||
}
|
||||
|
||||
const char *GetShaderTypeString(ShaderType type);
|
||||
std::string GetShaderDumpFileDirectory();
|
||||
std::string GetShaderDumpFileName(size_t shaderHash);
|
||||
|
||||
@@ -85,8 +85,9 @@ class ProgramImpl : angle::NonCopyable
|
||||
virtual std::unique_ptr<LinkEvent> link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::InfoLog &infoLog,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings) = 0;
|
||||
virtual GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) = 0;
|
||||
const gl::ProgramMergedVaryings &mergedVaryings,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks) = 0;
|
||||
virtual GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) = 0;
|
||||
|
||||
virtual void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) = 0;
|
||||
virtual void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) = 0;
|
||||
|
||||
@@ -564,8 +564,10 @@ uint8_t ProgramD3DMetadata::getCullDistanceArraySize() const
|
||||
class ProgramD3D::GetExecutableTask : public Closure, public d3d::Context
|
||||
{
|
||||
public:
|
||||
GetExecutableTask(const gl::Context *context, ProgramD3D *program)
|
||||
: mProgram(program), mContext(context)
|
||||
GetExecutableTask(const gl::Context *context,
|
||||
ProgramD3D *program,
|
||||
gl::ScopedShaderLinkLock &&shaderLock)
|
||||
: mProgram(program), mContext(context), mShaderLock(std::move(shaderLock))
|
||||
{}
|
||||
|
||||
virtual angle::Result run() = 0;
|
||||
@@ -608,6 +610,7 @@ class ProgramD3D::GetExecutableTask : public Closure, public d3d::Context
|
||||
const char *mStoredFunction = nullptr;
|
||||
unsigned int mStoredLine = 0;
|
||||
const gl::Context *mContext = nullptr;
|
||||
gl::ScopedShaderLinkLock mShaderLock;
|
||||
};
|
||||
|
||||
// ProgramD3D Implementation
|
||||
@@ -889,7 +892,7 @@ class ProgramD3D::LoadBinaryTask : public ProgramD3D::GetExecutableTask
|
||||
ProgramD3D *program,
|
||||
gl::BinaryInputStream *stream,
|
||||
gl::InfoLog &infoLog)
|
||||
: ProgramD3D::GetExecutableTask(context, program)
|
||||
: ProgramD3D::GetExecutableTask(context, program, gl::ScopedShaderLinkLock())
|
||||
{
|
||||
ASSERT(mProgram);
|
||||
ASSERT(stream);
|
||||
@@ -1723,13 +1726,17 @@ angle::Result ProgramD3D::getGeometryExecutableForPrimitiveType(d3d::Context *co
|
||||
class ProgramD3D::GetVertexExecutableTask : public ProgramD3D::GetExecutableTask
|
||||
{
|
||||
public:
|
||||
GetVertexExecutableTask(const gl::Context *context, ProgramD3D *program)
|
||||
: GetExecutableTask(context, program)
|
||||
GetVertexExecutableTask(const gl::Context *context,
|
||||
ProgramD3D *program,
|
||||
gl::ScopedShaderLinkLock &&shaderLock)
|
||||
: GetExecutableTask(context, program, std::move(shaderLock))
|
||||
{}
|
||||
angle::Result run() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::GetVertexExecutableTask::run");
|
||||
|
||||
gl::ScopedShaderLinkLock unlockAtEnd(std::move(mShaderLock));
|
||||
|
||||
ANGLE_TRY(mProgram->getVertexExecutableForCachedInputLayout(this, &mExecutable, &mInfoLog));
|
||||
|
||||
return angle::Result::Continue;
|
||||
@@ -1747,12 +1754,17 @@ void ProgramD3D::updateCachedInputLayoutFromShader(const gl::Context *context)
|
||||
class ProgramD3D::GetPixelExecutableTask : public ProgramD3D::GetExecutableTask
|
||||
{
|
||||
public:
|
||||
GetPixelExecutableTask(const gl::Context *context, ProgramD3D *program)
|
||||
: GetExecutableTask(context, program)
|
||||
GetPixelExecutableTask(const gl::Context *context,
|
||||
ProgramD3D *program,
|
||||
gl::ScopedShaderLinkLock &&shaderLock)
|
||||
: GetExecutableTask(context, program, std::move(shaderLock))
|
||||
{}
|
||||
angle::Result run() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::GetPixelExecutableTask::run");
|
||||
|
||||
gl::ScopedShaderLinkLock unlockAtEnd(std::move(mShaderLock));
|
||||
|
||||
if (!mProgram->mState.getAttachedShader(gl::ShaderType::Fragment))
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
@@ -1798,13 +1810,17 @@ class ProgramD3D::GetGeometryExecutableTask : public ProgramD3D::GetExecutableTa
|
||||
public:
|
||||
GetGeometryExecutableTask(const gl::Context *context,
|
||||
ProgramD3D *program,
|
||||
const gl::State &state)
|
||||
: GetExecutableTask(context, program), mState(state)
|
||||
const gl::State &state,
|
||||
gl::ScopedShaderLinkLock &&shaderLock)
|
||||
: GetExecutableTask(context, program, std::move(shaderLock)), mState(state)
|
||||
{}
|
||||
|
||||
angle::Result run() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::GetGeometryExecutableTask::run");
|
||||
|
||||
gl::ScopedShaderLinkLock unlockAtEnd(std::move(mShaderLock));
|
||||
|
||||
// Auto-generate the geometry shader here, if we expect to be using point rendering in
|
||||
// D3D11.
|
||||
if (mProgram->usesGeometryShader(mState, gl::PrimitiveMode::Points))
|
||||
@@ -1823,12 +1839,17 @@ class ProgramD3D::GetGeometryExecutableTask : public ProgramD3D::GetExecutableTa
|
||||
class ProgramD3D::GetComputeExecutableTask : public ProgramD3D::GetExecutableTask
|
||||
{
|
||||
public:
|
||||
GetComputeExecutableTask(const gl::Context *context, ProgramD3D *program)
|
||||
: GetExecutableTask(context, program)
|
||||
GetComputeExecutableTask(const gl::Context *context,
|
||||
ProgramD3D *program,
|
||||
gl::ScopedShaderLinkLock &&shaderLock)
|
||||
: GetExecutableTask(context, program, std::move(shaderLock))
|
||||
{}
|
||||
angle::Result run() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::GetComputeExecutableTask::run");
|
||||
|
||||
gl::ScopedShaderLinkLock unlockAtEnd(std::move(mShaderLock));
|
||||
|
||||
mProgram->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Compute);
|
||||
ShaderExecutableD3D *computeExecutable = nullptr;
|
||||
ANGLE_TRY(mProgram->getComputeExecutableForImage2DBindLayout(
|
||||
@@ -1973,8 +1994,10 @@ class ProgramD3D::ComputeProgramLinkEvent final : public LinkEvent
|
||||
std::shared_ptr<WaitableEvent> mWaitEvent;
|
||||
};
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramD3D::compileProgramExecutables(const gl::Context *context,
|
||||
gl::InfoLog &infoLog)
|
||||
std::unique_ptr<LinkEvent> ProgramD3D::compileProgramExecutables(
|
||||
const gl::Context *context,
|
||||
gl::InfoLog &infoLog,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::compileProgramExecutables");
|
||||
// Ensure the compiler is initialized to avoid race conditions.
|
||||
@@ -1984,10 +2007,12 @@ std::unique_ptr<LinkEvent> ProgramD3D::compileProgramExecutables(const gl::Conte
|
||||
return std::make_unique<LinkEventDone>(result);
|
||||
}
|
||||
|
||||
auto vertexTask = std::make_shared<GetVertexExecutableTask>(context, this);
|
||||
auto pixelTask = std::make_shared<GetPixelExecutableTask>(context, this);
|
||||
auto geometryTask =
|
||||
std::make_shared<GetGeometryExecutableTask>(context, this, context->getState());
|
||||
auto vertexTask = std::make_shared<GetVertexExecutableTask>(
|
||||
context, this, std::move((*shaderLocks)[gl::ShaderType::Vertex]));
|
||||
auto pixelTask = std::make_shared<GetPixelExecutableTask>(
|
||||
context, this, std::move((*shaderLocks)[gl::ShaderType::Fragment]));
|
||||
auto geometryTask = std::make_shared<GetGeometryExecutableTask>(
|
||||
context, this, context->getState(), std::move((*shaderLocks)[gl::ShaderType::Geometry]));
|
||||
bool useGS = usesGeometryShader(context->getState(), gl::PrimitiveMode::Points);
|
||||
gl::Shader *vertexShader = mState.getAttachedShader(gl::ShaderType::Vertex);
|
||||
gl::Shader *fragmentShader = mState.getAttachedShader(gl::ShaderType::Fragment);
|
||||
@@ -2000,8 +2025,10 @@ std::unique_ptr<LinkEvent> ProgramD3D::compileProgramExecutables(const gl::Conte
|
||||
vertexShaderD3D, fragmentShaderD3D);
|
||||
}
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramD3D::compileComputeExecutable(const gl::Context *context,
|
||||
gl::InfoLog &infoLog)
|
||||
std::unique_ptr<LinkEvent> ProgramD3D::compileComputeExecutable(
|
||||
const gl::Context *context,
|
||||
gl::InfoLog &infoLog,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::compileComputeExecutable");
|
||||
// Ensure the compiler is initialized to avoid race conditions.
|
||||
@@ -2010,7 +2037,8 @@ std::unique_ptr<LinkEvent> ProgramD3D::compileComputeExecutable(const gl::Contex
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(result);
|
||||
}
|
||||
auto computeTask = std::make_shared<GetComputeExecutableTask>(context, this);
|
||||
auto computeTask = std::make_shared<GetComputeExecutableTask>(
|
||||
context, this, std::move((*shaderLocks)[gl::ShaderType::Compute]));
|
||||
|
||||
std::shared_ptr<WaitableEvent> waitableEvent;
|
||||
|
||||
@@ -2082,7 +2110,8 @@ angle::Result ProgramD3D::getComputeExecutableForImage2DBindLayout(
|
||||
std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::InfoLog &infoLog,
|
||||
const gl::ProgramMergedVaryings & /*mergedVaryings*/)
|
||||
const gl::ProgramMergedVaryings & /*mergedVaryings*/,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::link");
|
||||
const auto &data = context->getState();
|
||||
@@ -2111,7 +2140,7 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
|
||||
|
||||
defineUniformsAndAssignRegisters(context);
|
||||
|
||||
return compileComputeExecutable(context, infoLog);
|
||||
return compileComputeExecutable(context, infoLog, shaderLocks);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2213,7 +2242,7 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
|
||||
updateCachedInputLayoutFromShader(context);
|
||||
}
|
||||
|
||||
return compileProgramExecutables(context, infoLog);
|
||||
return compileProgramExecutables(context, infoLog, shaderLocks);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -245,7 +245,8 @@ class ProgramD3D : public ProgramImpl
|
||||
std::unique_ptr<LinkEvent> link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::InfoLog &infoLog,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings) override;
|
||||
const gl::ProgramMergedVaryings &mergedVaryings,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks) override;
|
||||
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
|
||||
|
||||
void updateUniformBufferCache(const gl::Caps &caps);
|
||||
@@ -511,9 +512,11 @@ class ProgramD3D : public ProgramImpl
|
||||
const GLfloat *value);
|
||||
|
||||
std::unique_ptr<LinkEvent> compileProgramExecutables(const gl::Context *context,
|
||||
gl::InfoLog &infoLog);
|
||||
gl::InfoLog &infoLog,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks);
|
||||
std::unique_ptr<LinkEvent> compileComputeExecutable(const gl::Context *context,
|
||||
gl::InfoLog &infoLog);
|
||||
gl::InfoLog &infoLog,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks);
|
||||
|
||||
angle::Result loadBinaryShaderExecutables(d3d::Context *contextD3D,
|
||||
gl::BinaryInputStream *stream,
|
||||
|
||||
@@ -139,9 +139,22 @@ class ProgramGL::LinkTask final : public angle::Closure
|
||||
LinkTask(LinkImplFunctor &&functor) : mLinkImplFunctor(functor), mFallbackToMainContext(false)
|
||||
{}
|
||||
|
||||
void setShaderLocks(gl::ScopedShaderLinkLocks *shaderLocks) { mShaderLocks.swap(*shaderLocks); }
|
||||
|
||||
void operator()() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::LinkTask::run");
|
||||
|
||||
// Unlock the shaders at the end of the task.
|
||||
//
|
||||
// Note that there is a race condition if fallback to main is needed: by the time
|
||||
// resolveLink() is done, which calls LinkEventGL::wait() and subsequently link on the main
|
||||
// thread, the shader may get recompiled and the program would end up linking the new
|
||||
// shaders. This is not easily fixable with the current architecture, as there is no
|
||||
// guarantee resolveLink() is called before the following shader recompilation.
|
||||
gl::ScopedShaderLinkLocks unlockAtEnd;
|
||||
unlockAtEnd.swap(mShaderLocks);
|
||||
|
||||
mFallbackToMainContext = mLinkImplFunctor(mInfoLog);
|
||||
}
|
||||
|
||||
@@ -152,6 +165,8 @@ class ProgramGL::LinkTask final : public angle::Closure
|
||||
LinkImplFunctor mLinkImplFunctor;
|
||||
bool mFallbackToMainContext;
|
||||
std::string mInfoLog;
|
||||
|
||||
gl::ScopedShaderLinkLocks mShaderLocks;
|
||||
};
|
||||
|
||||
using PostLinkImplFunctor = std::function<angle::Result(bool, const std::string &)>;
|
||||
@@ -224,7 +239,8 @@ class ProgramGL::LinkEventGL final : public LinkEvent
|
||||
std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::InfoLog &infoLog,
|
||||
const gl::ProgramMergedVaryings & /*mergedVaryings*/)
|
||||
const gl::ProgramMergedVaryings & /*mergedVaryings*/,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::link");
|
||||
|
||||
@@ -472,15 +488,22 @@ std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context,
|
||||
return angle::Result::Continue;
|
||||
};
|
||||
|
||||
// |shaderLocks| is ignored except when the actual link is done in a job. They will be unlocked
|
||||
// by the caller. The post-link task does not use the shader's compile state in those cases
|
||||
// either.
|
||||
|
||||
if (mRenderer->hasNativeParallelCompile())
|
||||
{
|
||||
mFunctions->linkProgram(mProgramID);
|
||||
|
||||
return std::make_unique<LinkEventNativeParallel>(postLinkImplTask, mFunctions, mProgramID);
|
||||
}
|
||||
else if (workerPool->isAsync() &&
|
||||
else if (workerPool->isAsync() && !mFeatures.disableWorkerContexts.enabled &&
|
||||
(!mFeatures.dontRelinkProgramsInParallel.enabled || !mLinkedInParallel))
|
||||
{
|
||||
// Make sure the shaders are locked until the task is complete.
|
||||
linkTask->setShaderLocks(shaderLocks);
|
||||
|
||||
mLinkedInParallel = true;
|
||||
return std::make_unique<LinkEventGL>(workerPool, linkTask, postLinkImplTask);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,8 @@ class ProgramGL : public ProgramImpl
|
||||
std::unique_ptr<LinkEvent> link(const gl::Context *contextImpl,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::InfoLog &infoLog,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings) override;
|
||||
const gl::ProgramMergedVaryings &mergedVaryings,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks) override;
|
||||
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
|
||||
|
||||
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
|
||||
|
||||
@@ -397,10 +397,7 @@ void RendererGL::framebufferFetchBarrier()
|
||||
|
||||
bool RendererGL::bindWorkerContext(std::string *infoLog)
|
||||
{
|
||||
if (mFeatures.disableWorkerContexts.enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ASSERT(!mFeatures.disableWorkerContexts.enabled);
|
||||
|
||||
std::lock_guard<std::mutex> lock(mWorkerMutex);
|
||||
std::unique_ptr<WorkerContext> workerContext;
|
||||
|
||||
@@ -424,7 +424,7 @@ std::shared_ptr<WaitableCompileEvent> ShaderGL::compile(const gl::Context *conte
|
||||
result);
|
||||
}
|
||||
}
|
||||
else if (workerThreadPool->isAsync())
|
||||
else if (workerThreadPool->isAsync() && !features.disableWorkerContexts.enabled)
|
||||
{
|
||||
auto compileAndCheckShaderInWorkerFunctor = [this](const char *source) {
|
||||
return compileAndCheckShaderInWorker(source);
|
||||
|
||||
@@ -130,7 +130,8 @@ class ProgramMtl : public ProgramImpl
|
||||
std::unique_ptr<LinkEvent> link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::InfoLog &infoLog,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings) override;
|
||||
const gl::ProgramMergedVaryings &mergedVaryings,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks) override;
|
||||
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
|
||||
|
||||
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
|
||||
@@ -267,7 +268,8 @@ class ProgramMtl : public ProgramImpl
|
||||
|
||||
void linkResources(const gl::Context *context, const gl::ProgramLinkedResources &resources);
|
||||
std::unique_ptr<LinkEvent> compileMslShaderLibs(const gl::Context *context,
|
||||
gl::InfoLog &infoLog);
|
||||
gl::InfoLog &infoLog,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks);
|
||||
|
||||
mtl::BufferPool *getBufferPool(ContextMtl *context);
|
||||
|
||||
|
||||
@@ -625,7 +625,9 @@ std::unique_ptr<rx::LinkEvent> ProgramMtl::load(const gl::Context *context,
|
||||
ANGLE_PARALLEL_LINK_TRY(loadDefaultUniformBlocksInfo(context, stream));
|
||||
ANGLE_PARALLEL_LINK_TRY(loadInterfaceBlockInfo(context, stream));
|
||||
|
||||
return compileMslShaderLibs(context, infoLog);
|
||||
// Shaders are unused
|
||||
gl::ScopedShaderLinkLocks noOpShaderLocks;
|
||||
return compileMslShaderLibs(context, infoLog, &noOpShaderLocks);
|
||||
}
|
||||
|
||||
void ProgramMtl::save(const gl::Context *context, gl::BinaryOutputStream *stream)
|
||||
@@ -646,7 +648,8 @@ void ProgramMtl::setSeparable(bool separable)
|
||||
std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::InfoLog &infoLog,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings)
|
||||
const gl::ProgramMergedVaryings &mergedVaryings,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks)
|
||||
{
|
||||
ContextMtl *contextMtl = mtl::GetImpl(context);
|
||||
|
||||
@@ -666,7 +669,7 @@ std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context,
|
||||
mState.getExecutable().getTransformFeedbackBufferCount()));
|
||||
mMslXfbOnlyVertexShaderInfo = mMslShaderTranslateInfo[gl::ShaderType::Vertex];
|
||||
|
||||
return compileMslShaderLibs(context, infoLog);
|
||||
return compileMslShaderLibs(context, infoLog, shaderLocks);
|
||||
}
|
||||
|
||||
void ProgramMtl::linkUpdateHasFlatAttributes(const gl::Context *context)
|
||||
@@ -700,14 +703,18 @@ class ProgramMtl::CompileMslTask final : public angle::Closure
|
||||
public:
|
||||
CompileMslTask(ContextMtl *context,
|
||||
mtl::TranslatedShaderInfo *translatedMslInfo,
|
||||
const std::map<std::string, std::string> &substitutionMacros)
|
||||
const std::map<std::string, std::string> &substitutionMacros,
|
||||
gl::ScopedShaderLinkLock &&shaderLock)
|
||||
: mContext(context),
|
||||
mTranslatedMslInfo(translatedMslInfo),
|
||||
mSubstitutionMacros(substitutionMacros)
|
||||
mSubstitutionMacros(substitutionMacros),
|
||||
mShaderLock(std::move(shaderLock))
|
||||
{}
|
||||
|
||||
void operator()() override
|
||||
{
|
||||
gl::ScopedShaderLinkLock unlockAtEnd(std::move(mShaderLock));
|
||||
|
||||
mResult = CreateMslShaderLib(mContext, mInfoLog, mTranslatedMslInfo, mSubstitutionMacros);
|
||||
}
|
||||
|
||||
@@ -726,6 +733,7 @@ class ProgramMtl::CompileMslTask final : public angle::Closure
|
||||
gl::InfoLog mInfoLog;
|
||||
mtl::TranslatedShaderInfo *mTranslatedMslInfo;
|
||||
std::map<std::string, std::string> mSubstitutionMacros;
|
||||
gl::ScopedShaderLinkLock mShaderLock;
|
||||
angle::Result mResult = angle::Result::Continue;
|
||||
};
|
||||
|
||||
@@ -767,7 +775,8 @@ class ProgramMtl::ProgramLinkEvent final : public LinkEvent
|
||||
};
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramMtl::compileMslShaderLibs(const gl::Context *context,
|
||||
gl::InfoLog &infoLog)
|
||||
gl::InfoLog &infoLog,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramMtl::compileMslShaderLibs");
|
||||
|
||||
@@ -792,12 +801,13 @@ std::unique_ptr<LinkEvent> ProgramMtl::compileMslShaderLibs(const gl::Context *c
|
||||
{
|
||||
if (asyncCompile)
|
||||
{
|
||||
auto task =
|
||||
std::make_shared<ProgramMtl::CompileMslTask>(contextMtl, translateInfo, macros);
|
||||
auto task = std::make_shared<ProgramMtl::CompileMslTask>(
|
||||
contextMtl, translateInfo, macros, std::move((*shaderLocks)[shaderType]));
|
||||
asyncTasks.push_back(task);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore |shaderLocks|, the caller will unlock them.
|
||||
ANGLE_PARALLEL_LINK_TRY(
|
||||
CreateMslShaderLib(contextMtl, infoLog, translateInfo, macros));
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ void ProgramNULL::setSeparable(bool separable) {}
|
||||
std::unique_ptr<LinkEvent> ProgramNULL::link(const gl::Context *contextImpl,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::InfoLog &infoLog,
|
||||
const gl::ProgramMergedVaryings & /*mergedVaryings*/)
|
||||
const gl::ProgramMergedVaryings & /*mergedVaryings*/,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks)
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(angle::Result::Continue);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,8 @@ class ProgramNULL : public ProgramImpl
|
||||
std::unique_ptr<LinkEvent> link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::InfoLog &infoLog,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings) override;
|
||||
const gl::ProgramMergedVaryings &mergedVaryings,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks) override;
|
||||
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
|
||||
|
||||
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
|
||||
|
||||
@@ -29,6 +29,7 @@ class LinkTask final : public vk::Context, public angle::Closure
|
||||
const gl::ProgramState &state,
|
||||
const gl::ProgramExecutable &glExecutable,
|
||||
ProgramExecutableVk *executable,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks,
|
||||
bool isGLES1,
|
||||
vk::PipelineRobustness pipelineRobustness,
|
||||
vk::PipelineProtectedAccess pipelineProtectedAccess)
|
||||
@@ -39,7 +40,9 @@ class LinkTask final : public vk::Context, public angle::Closure
|
||||
mIsGLES1(isGLES1),
|
||||
mPipelineRobustness(pipelineRobustness),
|
||||
mPipelineProtectedAccess(pipelineProtectedAccess)
|
||||
{}
|
||||
{
|
||||
mShaderLocks.swap(*shaderLocks);
|
||||
}
|
||||
|
||||
void operator()() override;
|
||||
|
||||
@@ -83,6 +86,7 @@ class LinkTask final : public vk::Context, public angle::Closure
|
||||
const gl::ProgramState &mState;
|
||||
const gl::ProgramExecutable &mGlExecutable;
|
||||
ProgramExecutableVk *mExecutable;
|
||||
gl::ScopedShaderLinkLocks mShaderLocks;
|
||||
bool mIsGLES1;
|
||||
vk::PipelineRobustness mPipelineRobustness;
|
||||
vk::PipelineProtectedAccess mPipelineProtectedAccess;
|
||||
@@ -101,6 +105,10 @@ void LinkTask::operator()()
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVk::LinkTask::run");
|
||||
|
||||
// Unlock the shaders at the end of the task.
|
||||
gl::ScopedShaderLinkLocks unlockAtEnd;
|
||||
unlockAtEnd.swap(mShaderLocks);
|
||||
|
||||
// Warm up the pipeline cache by creating a few placeholder pipelines. This is not done for
|
||||
// separable programs, and is deferred to when the program pipeline is finalized.
|
||||
//
|
||||
@@ -309,7 +317,8 @@ void ProgramVk::setSeparable(bool separable)
|
||||
std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::InfoLog &infoLog,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings)
|
||||
const gl::ProgramMergedVaryings &mergedVaryings,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVk::link");
|
||||
|
||||
@@ -358,7 +367,7 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
|
||||
}
|
||||
|
||||
std::shared_ptr<LinkTask> linkTask = std::make_shared<LinkTask>(
|
||||
contextVk->getRenderer(), mState, programExecutable, &mExecutable,
|
||||
contextVk->getRenderer(), mState, programExecutable, &mExecutable, shaderLocks,
|
||||
context->getState().isGLES1(), contextVk->pipelineRobustness(),
|
||||
contextVk->pipelineProtectedAccess());
|
||||
return std::make_unique<LinkEventVulkan>(context->getShaderCompileThreadPool(), linkTask);
|
||||
|
||||
@@ -39,7 +39,8 @@ class ProgramVk : public ProgramImpl
|
||||
std::unique_ptr<LinkEvent> link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::InfoLog &infoLog,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings) override;
|
||||
const gl::ProgramMergedVaryings &mergedVaryings,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks) override;
|
||||
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
|
||||
|
||||
angle::Result syncState(const gl::Context *context,
|
||||
|
||||
Reference in New Issue
Block a user