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:
Shahbaz Youssefi
2023-08-11 17:07:16 -04:00
committed by Angle LUCI CQ
parent f9e3f67430
commit 424f43e40e
17 changed files with 222 additions and 56 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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));
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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,