mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-01 05:48:11 +03:00
Support for link to be entirely parallelized
The link job is split as such:
- Front-end link
- Back-end link
- Independent back-end link subtasks (typically native driver compile
jobs)
- Post-link finalization
Each step depends on the previous. These steps are executed as such:
1. Program::link calls into ProgramImpl::link
- ProgramImpl::link runs whatever needs the Context, such as releasing
resources
- ProgramImpl::link returns a LinkTask
2. Program::link implements a closure that calls the front-end link and
passes the results to the backend's LinkTask.
3. The LinkTask potentially returns a set of LinkSubTasks to be
scheduled by the worker pool
4. Once the link is resolved, the post-link finalization is run
In the above, steps 1 and 4 are done under the share group lock. Steps
2 and 3 can be done in threads or without holding the share group lock
if the backend supports it. Step 2 is not yet made independent of the
Context on some backends, and a frontend feature is used to make that
step either run on the main thread or as a worker thread.
Bug: angleproject:8297
Change-Id: I12f1e6bbaf365543dfcac969e166e0b5aa622104
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4808191
Reviewed-by: Charlie Lao <cclao@google.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
committed by
Angle LUCI CQ
parent
3c5728f19c
commit
68bfa1edf5
@@ -161,6 +161,13 @@ struct FrontendFeatures : FeatureSetBase
|
||||
&members, "http://anglebug.com/8280"
|
||||
};
|
||||
|
||||
FeatureInfo linkJobIsNotThreadSafe = {
|
||||
"linkJobIsNotThreadSafe",
|
||||
FeatureCategory::FrontendWorkarounds,
|
||||
"If true, parts of the link job cannot be parallelized",
|
||||
&members, "http://anglebug.com/8297"
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
inline FrontendFeatures::FrontendFeatures() = default;
|
||||
|
||||
@@ -161,6 +161,14 @@
|
||||
"Check the filesystem for translated shaders to use instead of the shader translator's"
|
||||
],
|
||||
"issue": "http://anglebug.com/8280"
|
||||
},
|
||||
{
|
||||
"name": "link_job_is_not_thread_safe",
|
||||
"category": "Workarounds",
|
||||
"description": [
|
||||
"If true, parts of the link job cannot be parallelized"
|
||||
],
|
||||
"issue": "http://anglebug.com/8297"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -182,6 +182,7 @@ void LoadShInterfaceBlock(gl::BinaryInputStream *stream, sh::InterfaceBlock *blo
|
||||
|
||||
CompiledShaderState::CompiledShaderState(gl::ShaderType type)
|
||||
: shaderType(type),
|
||||
successfullyCompiled(false),
|
||||
shaderVersion(100),
|
||||
hasClipDistance(false),
|
||||
hasDiscard(false),
|
||||
|
||||
@@ -54,6 +54,8 @@ struct CompiledShaderState
|
||||
|
||||
const gl::ShaderType shaderType;
|
||||
|
||||
bool successfullyCompiled;
|
||||
|
||||
int shaderVersion;
|
||||
std::string translatedSource;
|
||||
sh::BinaryBlob compiledBinary;
|
||||
|
||||
@@ -9374,6 +9374,11 @@ std::shared_ptr<angle::WorkerThreadPool> Context::getShaderCompileThreadPool() c
|
||||
return mDisplay->getSingleThreadPool();
|
||||
}
|
||||
|
||||
std::shared_ptr<angle::WorkerThreadPool> Context::getSingleThreadPool() const
|
||||
{
|
||||
return mDisplay->getSingleThreadPool();
|
||||
}
|
||||
|
||||
std::shared_ptr<angle::WorkerThreadPool> Context::getWorkerThreadPool() const
|
||||
{
|
||||
return mDisplay->getMultiThreadPool();
|
||||
|
||||
@@ -700,6 +700,9 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
|
||||
// GL_KHR_parallel_shader_compile
|
||||
std::shared_ptr<angle::WorkerThreadPool> getShaderCompileThreadPool() const;
|
||||
|
||||
// Single-threaded pool; runs everything instantly
|
||||
std::shared_ptr<angle::WorkerThreadPool> getSingleThreadPool() const;
|
||||
|
||||
// Generic multithread pool.
|
||||
std::shared_ptr<angle::WorkerThreadPool> getWorkerThreadPool() const;
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "libANGLE/renderer/ContextImpl.h"
|
||||
#include "libANGLE/renderer/GLImplFactory.h"
|
||||
#include "libANGLE/renderer/ProgramImpl.h"
|
||||
#include "libANGLE/trace.h"
|
||||
#include "platform/PlatformMethods.h"
|
||||
#include "platform/autogen/FrontendFeatures_autogen.h"
|
||||
|
||||
@@ -372,6 +373,34 @@ const std::string GetResourceName(const T &resource)
|
||||
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
// Provides a mechanism to access the result of asynchronous linking.
|
||||
class LinkEvent : angle::NonCopyable
|
||||
{
|
||||
public:
|
||||
virtual ~LinkEvent() {}
|
||||
|
||||
// Please be aware that these methods may be called under a gl::Context other
|
||||
// than the one where the LinkEvent was created.
|
||||
//
|
||||
// Waits until the linking is actually done. Returns true if the linking
|
||||
// succeeded, false otherwise.
|
||||
virtual angle::Result wait(const gl::Context *context) = 0;
|
||||
// Peeks whether the linking is still ongoing.
|
||||
virtual bool isLinking() = 0;
|
||||
};
|
||||
|
||||
// Wraps an already done linking.
|
||||
class LinkEventDone final : public LinkEvent
|
||||
{
|
||||
public:
|
||||
LinkEventDone(angle::Result result) : mResult(result) {}
|
||||
angle::Result wait(const gl::Context *context) override { return mResult; }
|
||||
bool isLinking() override { return false; }
|
||||
|
||||
private:
|
||||
angle::Result mResult;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
const char *GetLinkMismatchErrorString(LinkMismatchError linkError)
|
||||
@@ -515,7 +544,7 @@ struct Program::LinkingState
|
||||
LinkingVariables linkingVariables;
|
||||
ProgramLinkedResources resources;
|
||||
egl::BlobCache::Key programHash;
|
||||
std::unique_ptr<rx::LinkEvent> linkEvent;
|
||||
std::unique_ptr<LinkEvent> linkEvent;
|
||||
bool linkingFromBinary;
|
||||
};
|
||||
|
||||
@@ -976,6 +1005,182 @@ ShaderType ProgramState::getAttachedTransformFeedbackStage() const
|
||||
return ShaderType::Vertex;
|
||||
}
|
||||
|
||||
// The common portion of parallel link and load jobs
|
||||
class Program::MainLinkLoadTask : public angle::Closure
|
||||
{
|
||||
public:
|
||||
MainLinkLoadTask(const std::shared_ptr<angle::WorkerThreadPool> &subTaskWorkerPool,
|
||||
ProgramState *state,
|
||||
std::shared_ptr<rx::LinkTask> &&linkTask)
|
||||
: mSubTaskWorkerPool(subTaskWorkerPool), mState(*state), mLinkTask(std::move(linkTask))
|
||||
{
|
||||
ASSERT(subTaskWorkerPool.get());
|
||||
}
|
||||
~MainLinkLoadTask() override = default;
|
||||
|
||||
angle::Result getResult(const Context *context)
|
||||
{
|
||||
InfoLog &infoLog = mState.getExecutable().getInfoLog();
|
||||
|
||||
ANGLE_TRY(mResult);
|
||||
ANGLE_TRY(mLinkTask->getResult(context, infoLog));
|
||||
|
||||
for (const std::shared_ptr<rx::LinkSubTask> &task : mSubTasks)
|
||||
{
|
||||
ANGLE_TRY(task->getResult(context, infoLog));
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
void waitSubTasks() { angle::WaitableEvent::WaitMany(&mSubTaskWaitableEvents); }
|
||||
|
||||
bool areSubTasksLinking()
|
||||
{
|
||||
return !mLinkTask->isLinkingInternally() &&
|
||||
!angle::WaitableEvent::AllReady(&mSubTaskWaitableEvents);
|
||||
}
|
||||
|
||||
protected:
|
||||
void scheduleSubTasks(const std::vector<std::shared_ptr<rx::LinkSubTask>> &subTasks)
|
||||
{
|
||||
mSubTaskWaitableEvents.reserve(subTasks.size());
|
||||
for (const std::shared_ptr<rx::LinkSubTask> &subTask : subTasks)
|
||||
{
|
||||
mSubTaskWaitableEvents.push_back(mSubTaskWorkerPool->postWorkerTask(subTask));
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<angle::WorkerThreadPool> mSubTaskWorkerPool;
|
||||
ProgramState &mState;
|
||||
std::shared_ptr<rx::LinkTask> mLinkTask;
|
||||
|
||||
// Subtask wait events
|
||||
std::vector<std::shared_ptr<rx::LinkSubTask>> mSubTasks;
|
||||
std::vector<std::shared_ptr<angle::WaitableEvent>> mSubTaskWaitableEvents;
|
||||
|
||||
// The result of the front-end portion of the link. The backend's result is retrieved via
|
||||
// mLinkTask->getResult(). The subtask results are retrieved via mSubTasks similarly.
|
||||
angle::Result mResult;
|
||||
};
|
||||
|
||||
class Program::MainLinkTask final : public Program::MainLinkLoadTask
|
||||
{
|
||||
public:
|
||||
MainLinkTask(const std::shared_ptr<angle::WorkerThreadPool> &subTaskWorkerPool,
|
||||
const Caps &caps,
|
||||
const Limitations &limitations,
|
||||
const Version &clientVersion,
|
||||
bool isWebGL,
|
||||
Program *program,
|
||||
ProgramState *state,
|
||||
LinkingVariables *linkingVariables,
|
||||
ProgramLinkedResources *resources,
|
||||
std::shared_ptr<rx::LinkTask> &&linkTask)
|
||||
: MainLinkLoadTask(subTaskWorkerPool, state, std::move(linkTask)),
|
||||
mCaps(caps),
|
||||
mLimitations(limitations),
|
||||
mClientVersion(clientVersion),
|
||||
mIsWebGL(isWebGL),
|
||||
mProgram(program),
|
||||
mLinkingVariables(linkingVariables),
|
||||
mResources(resources)
|
||||
{}
|
||||
~MainLinkTask() override = default;
|
||||
|
||||
void operator()() override { mResult = linkImpl(); }
|
||||
|
||||
private:
|
||||
angle::Result linkImpl();
|
||||
|
||||
// State needed for link
|
||||
const Caps &mCaps;
|
||||
const Limitations &mLimitations;
|
||||
const Version mClientVersion;
|
||||
const bool mIsWebGL;
|
||||
Program *mProgram;
|
||||
LinkingVariables *mLinkingVariables;
|
||||
ProgramLinkedResources *mResources;
|
||||
};
|
||||
|
||||
class Program::MainLoadTask final : public Program::MainLinkLoadTask
|
||||
{
|
||||
public:
|
||||
MainLoadTask(const std::shared_ptr<angle::WorkerThreadPool> &subTaskWorkerPool,
|
||||
Program *program,
|
||||
ProgramState *state,
|
||||
std::shared_ptr<rx::LinkTask> &&loadTask)
|
||||
: MainLinkLoadTask(subTaskWorkerPool, state, std::move(loadTask))
|
||||
{}
|
||||
~MainLoadTask() override = default;
|
||||
|
||||
void operator()() override { mResult = loadImpl(); }
|
||||
|
||||
private:
|
||||
angle::Result loadImpl();
|
||||
};
|
||||
|
||||
class Program::MainLinkLoadEvent final : public LinkEvent
|
||||
{
|
||||
public:
|
||||
MainLinkLoadEvent(const std::shared_ptr<MainLinkLoadTask> &linkTask,
|
||||
const std::shared_ptr<angle::WaitableEvent> &waitEvent)
|
||||
: mLinkTask(linkTask), mWaitableEvent(waitEvent)
|
||||
{}
|
||||
~MainLinkLoadEvent() override {}
|
||||
|
||||
angle::Result wait(const gl::Context *context) override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "Program::MainLinkLoadEvent::wait");
|
||||
|
||||
mWaitableEvent->wait();
|
||||
mLinkTask->waitSubTasks();
|
||||
|
||||
return mLinkTask->getResult(context);
|
||||
}
|
||||
bool isLinking() override
|
||||
{
|
||||
return !mWaitableEvent->isReady() || mLinkTask->areSubTasksLinking();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<MainLinkLoadTask> mLinkTask;
|
||||
std::shared_ptr<angle::WaitableEvent> mWaitableEvent;
|
||||
};
|
||||
|
||||
angle::Result Program::MainLinkTask::linkImpl()
|
||||
{
|
||||
ProgramMergedVaryings mergedVaryings;
|
||||
|
||||
// Do the front-end portion of the link.
|
||||
ANGLE_TRY(mProgram->linkJobImpl(mCaps, mLimitations, mClientVersion, mIsWebGL,
|
||||
mLinkingVariables, mResources, &mergedVaryings));
|
||||
|
||||
// Next, do the backend portion of the link. If there are any subtasks to be scheduled, they
|
||||
// are collected now.
|
||||
std::vector<std::shared_ptr<rx::LinkSubTask>> subTasks =
|
||||
mLinkTask->link(*mResources, mergedVaryings);
|
||||
|
||||
// Must be after backend's link to avoid misleading the linker about input/output variables.
|
||||
mState.updateProgramInterfaceInputs();
|
||||
mState.updateProgramInterfaceOutputs();
|
||||
|
||||
// Schedule the subtasks
|
||||
scheduleSubTasks(subTasks);
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result Program::MainLoadTask::loadImpl()
|
||||
{
|
||||
std::vector<std::shared_ptr<rx::LinkSubTask>> subTasks = mLinkTask->load();
|
||||
|
||||
// Schedule the subtasks
|
||||
scheduleSubTasks(subTasks);
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
Program::Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, ShaderProgramID handle)
|
||||
: mSerial(factory->generateSerial()),
|
||||
mState(factory),
|
||||
@@ -1111,6 +1316,8 @@ void Program::bindFragmentOutputIndex(GLuint index, const char *name)
|
||||
|
||||
void Program::makeNewExecutable(const Context *context)
|
||||
{
|
||||
ASSERT(!mLinkingState);
|
||||
|
||||
// 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.
|
||||
mLinked = false;
|
||||
@@ -1119,7 +1326,7 @@ void Program::makeNewExecutable(const Context *context)
|
||||
|
||||
// By default, set the link event as failing. If link succeeds, it will be replaced by the
|
||||
// appropriate event.
|
||||
mLinkingState->linkEvent = std::make_unique<rx::LinkEventDone>(angle::Result::Stop);
|
||||
mLinkingState->linkEvent = std::make_unique<LinkEventDone>(angle::Result::Stop);
|
||||
|
||||
InstallExecutable(
|
||||
context,
|
||||
@@ -1191,7 +1398,7 @@ angle::Result Program::linkImpl(const Context *context)
|
||||
mState.mInfoLog.reset();
|
||||
|
||||
// Validate we have properly attached shaders before checking the cache.
|
||||
if (!linkValidateShaders(context))
|
||||
if (!linkValidateShaders())
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
@@ -1224,41 +1431,76 @@ angle::Result Program::linkImpl(const Context *context)
|
||||
const Version &clientVersion = context->getClientVersion();
|
||||
const bool isWebGL = context->isWebGL();
|
||||
|
||||
// Ask the backend to prepare the link task.
|
||||
std::shared_ptr<rx::LinkTask> linkTask;
|
||||
ANGLE_TRY(mProgram->link(context, &linkTask));
|
||||
|
||||
std::unique_ptr<LinkingState> linkingState = std::make_unique<LinkingState>();
|
||||
|
||||
// Prepare the main link job
|
||||
std::shared_ptr<MainLinkLoadTask> mainLinkTask(new MainLinkTask(
|
||||
context->getShaderCompileThreadPool(), caps, limitations, clientVersion, isWebGL, this,
|
||||
&mState, &linkingState->linkingVariables, &linkingState->resources, std::move(linkTask)));
|
||||
|
||||
// While the subtasks are currently always thread-safe, the main task is not safe on all
|
||||
// backends. A front-end feature selects whether the single-threaded pool must be used.
|
||||
std::shared_ptr<angle::WorkerThreadPool> mainLinkWorkerPool =
|
||||
context->getFrontendFeatures().linkJobIsNotThreadSafe.enabled
|
||||
? context->getSingleThreadPool()
|
||||
: context->getShaderCompileThreadPool();
|
||||
|
||||
// TODO: add the possibility to perform this in an unlocked tail call. http://anglebug.com/8297
|
||||
std::shared_ptr<angle::WaitableEvent> mainLinkEvent =
|
||||
mainLinkWorkerPool->postWorkerTask(mainLinkTask);
|
||||
|
||||
mLinkingState = std::move(linkingState);
|
||||
mLinkingState->linkingFromBinary = false;
|
||||
mLinkingState->programHash = programHash;
|
||||
mLinkingState->linkEvent = std::make_unique<MainLinkLoadEvent>(mainLinkTask, mainLinkEvent);
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result Program::linkJobImpl(const Caps &caps,
|
||||
const Limitations &limitations,
|
||||
const Version &clientVersion,
|
||||
bool isWebGL,
|
||||
LinkingVariables *linkingVariables,
|
||||
ProgramLinkedResources *resources,
|
||||
ProgramMergedVaryings *mergedVaryingsOut)
|
||||
{
|
||||
// Cache load failed, fall through to normal linking.
|
||||
unlink();
|
||||
|
||||
// Re-link shaders after the unlink call.
|
||||
linkShaders();
|
||||
|
||||
ProgramMergedVaryings mergedVaryings;
|
||||
LinkingVariables &linkingVariables = mLinkingState->linkingVariables;
|
||||
ProgramLinkedResources &resources = mLinkingState->resources;
|
||||
|
||||
linkingVariables.initForProgram(mState);
|
||||
resources.init(&mState.mExecutable->mUniformBlocks, &mState.mExecutable->mUniforms,
|
||||
&mState.mExecutable->mUniformNames, &mState.mExecutable->mUniformMappedNames,
|
||||
&mState.mExecutable->mShaderStorageBlocks, &mState.mExecutable->mBufferVariables,
|
||||
&mState.mExecutable->mAtomicCounterBuffers);
|
||||
linkingVariables->initForProgram(mState);
|
||||
resources->init(&mState.mExecutable->mUniformBlocks, &mState.mExecutable->mUniforms,
|
||||
&mState.mExecutable->mUniformNames, &mState.mExecutable->mUniformMappedNames,
|
||||
&mState.mExecutable->mShaderStorageBlocks,
|
||||
&mState.mExecutable->mBufferVariables,
|
||||
&mState.mExecutable->mAtomicCounterBuffers);
|
||||
|
||||
updateLinkedShaderStages();
|
||||
|
||||
InitUniformBlockLinker(mState, &resources.uniformBlockLinker);
|
||||
InitShaderStorageBlockLinker(mState, &resources.shaderStorageBlockLinker);
|
||||
InitUniformBlockLinker(mState, &resources->uniformBlockLinker);
|
||||
InitShaderStorageBlockLinker(mState, &resources->shaderStorageBlockLinker);
|
||||
|
||||
if (mState.mAttachedShaders[ShaderType::Compute])
|
||||
{
|
||||
GLuint combinedImageUniforms = 0;
|
||||
if (!linkUniforms(caps, clientVersion, &resources.unusedUniforms, &combinedImageUniforms))
|
||||
if (!linkUniforms(caps, clientVersion, &resources->unusedUniforms, &combinedImageUniforms))
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
GLuint combinedShaderStorageBlocks = 0u;
|
||||
if (!LinkValidateProgramInterfaceBlocks(
|
||||
caps, clientVersion, isWebGL, mState.mExecutable->getLinkedShaderStages(),
|
||||
resources, mState.mInfoLog, &combinedShaderStorageBlocks))
|
||||
*resources, mState.mInfoLog, &combinedShaderStorageBlocks))
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
// [OpenGL ES 3.1] Chapter 8.22 Page 203:
|
||||
@@ -1274,38 +1516,38 @@ angle::Result Program::linkImpl(const Context *context)
|
||||
"and active fragment shader outputs exceeds "
|
||||
"MAX_COMBINED_SHADER_OUTPUT_RESOURCES ("
|
||||
<< caps.maxCombinedShaderOutputResources << ")";
|
||||
return angle::Result::Continue;
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!linkAttributes(caps, limitations, isWebGL))
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
if (!linkVaryings())
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
GLuint combinedImageUniforms = 0;
|
||||
if (!linkUniforms(caps, clientVersion, &resources.unusedUniforms, &combinedImageUniforms))
|
||||
if (!linkUniforms(caps, clientVersion, &resources->unusedUniforms, &combinedImageUniforms))
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
GLuint combinedShaderStorageBlocks = 0u;
|
||||
if (!LinkValidateProgramInterfaceBlocks(
|
||||
caps, clientVersion, isWebGL, mState.mExecutable->getLinkedShaderStages(),
|
||||
resources, mState.mInfoLog, &combinedShaderStorageBlocks))
|
||||
*resources, mState.mInfoLog, &combinedShaderStorageBlocks))
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
if (!LinkValidateProgramGlobalNames(mState.mInfoLog, getExecutable(), linkingVariables))
|
||||
if (!LinkValidateProgramGlobalNames(mState.mInfoLog, getExecutable(), *linkingVariables))
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
const SharedCompiledShaderState &vertexShader = mState.mAttachedShaders[ShaderType::Vertex];
|
||||
@@ -1325,7 +1567,7 @@ angle::Result Program::linkImpl(const Context *context)
|
||||
fragmentShader->activeOutputVariables, fragmentShader->shaderVersion,
|
||||
mState.mFragmentOutputLocations, mState.mFragmentOutputIndexes))
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
mState.mExecutable->mPODStruct.hasDiscard = fragmentShader->hasDiscard;
|
||||
@@ -1336,25 +1578,17 @@ angle::Result Program::linkImpl(const Context *context)
|
||||
mState.mExecutable->mPODStruct.specConstUsageBits |= fragmentShader->specConstUsageBits;
|
||||
}
|
||||
|
||||
mergedVaryings = GetMergedVaryingsFromLinkingVariables(linkingVariables);
|
||||
*mergedVaryingsOut = GetMergedVaryingsFromLinkingVariables(*linkingVariables);
|
||||
if (!mState.mExecutable->linkMergedVaryings(caps, limitations, clientVersion, isWebGL,
|
||||
mergedVaryings, linkingVariables, isSeparable(),
|
||||
&resources.varyingPacking))
|
||||
*mergedVaryingsOut, *linkingVariables,
|
||||
isSeparable(), &resources->varyingPacking))
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
}
|
||||
|
||||
mState.mExecutable->saveLinkedStateInfo(mState);
|
||||
|
||||
mLinkingState->linkingFromBinary = false;
|
||||
mLinkingState->programHash = programHash;
|
||||
mLinkingState->linkEvent = mProgram->link(context, resources, std::move(mergedVaryings));
|
||||
|
||||
// Must be after mProgram->link() to avoid misleading the linker about output variables.
|
||||
mState.updateProgramInterfaceInputs();
|
||||
mState.updateProgramInterfaceOutputs();
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
@@ -1556,8 +1790,36 @@ angle::Result Program::loadBinary(const Context *context,
|
||||
mDirtyBits.set(uniformBlockIndex);
|
||||
}
|
||||
|
||||
// If load returns incomplete, we know for sure that the binary is not compatible with the
|
||||
// backend. The loaded binary could have been read from the on-disk shader cache and be
|
||||
// corrupted or serialized with different revision and subsystem id than the currently loaded
|
||||
// backend. Returning 'Incomplete' to the caller results in link happening using the original
|
||||
// shader sources.
|
||||
std::shared_ptr<rx::LinkTask> loadTask;
|
||||
angle::Result result = mProgram->load(context, &stream, &loadTask);
|
||||
if (result == angle::Result::Incomplete)
|
||||
{
|
||||
return angle::Result::Incomplete;
|
||||
}
|
||||
ANGLE_TRY(result);
|
||||
|
||||
std::unique_ptr<LinkEvent> loadEvent;
|
||||
if (loadTask)
|
||||
{
|
||||
std::shared_ptr<MainLinkLoadTask> mainLoadTask(new MainLoadTask(
|
||||
context->getShaderCompileThreadPool(), this, &mState, std::move(loadTask)));
|
||||
|
||||
std::shared_ptr<angle::WaitableEvent> mainLoadEvent =
|
||||
context->getShaderCompileThreadPool()->postWorkerTask(mainLoadTask);
|
||||
loadEvent = std::make_unique<MainLinkLoadEvent>(mainLoadTask, mainLoadEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
loadEvent = std::make_unique<LinkEventDone>(angle::Result::Continue);
|
||||
}
|
||||
|
||||
mLinkingState->linkingFromBinary = true;
|
||||
mLinkingState->linkEvent = mProgram->load(context, &stream);
|
||||
mLinkingState->linkEvent = std::move(loadEvent);
|
||||
|
||||
*successOut = true;
|
||||
|
||||
@@ -2732,7 +2994,7 @@ GLsizei Program::getTransformFeedbackVaryingMaxLength() const
|
||||
}
|
||||
}
|
||||
|
||||
bool Program::linkValidateShaders(const Context *context)
|
||||
bool Program::linkValidateShaders()
|
||||
{
|
||||
const ShaderMap<SharedCompiledShaderState> &shaders = mState.mAttachedShaders;
|
||||
|
||||
@@ -2754,19 +3016,15 @@ bool Program::linkValidateShaders(const Context *context)
|
||||
Optional<int> version;
|
||||
for (ShaderType shaderType : kAllGraphicsShaderTypes)
|
||||
{
|
||||
Shader *shaderObj = getAttachedShader(shaderType);
|
||||
ASSERT(!shaderObj || shaderObj->getType() == shaderType);
|
||||
|
||||
const SharedCompiledShaderState &shader = shaders[shaderType];
|
||||
ASSERT(!shader || shader->shaderType == shaderType);
|
||||
|
||||
if (!shaderObj)
|
||||
if (!shader)
|
||||
{
|
||||
ASSERT(!shader);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!shaderObj->isCompiled(context))
|
||||
if (!shader->successfullyCompiled)
|
||||
{
|
||||
mState.mInfoLog << ShaderTypeToString(shaderType) << " shader is not compiled.";
|
||||
return false;
|
||||
|
||||
@@ -851,7 +851,15 @@ class Program final : public LabeledObject, public angle::Subject
|
||||
}
|
||||
|
||||
private:
|
||||
class MainLinkLoadTask;
|
||||
class MainLoadTask;
|
||||
class MainLinkTask;
|
||||
class MainLinkLoadEvent;
|
||||
|
||||
friend class ProgramPipeline;
|
||||
friend class MainLinkLoadTask;
|
||||
friend class MainLoadTask;
|
||||
friend class MainLinkTask;
|
||||
|
||||
struct LinkingState;
|
||||
~Program() override;
|
||||
@@ -863,10 +871,17 @@ class Program final : public LabeledObject, public angle::Subject
|
||||
void deleteSelf(const Context *context);
|
||||
|
||||
angle::Result linkImpl(const Context *context);
|
||||
angle::Result linkJobImpl(const Caps &caps,
|
||||
const Limitations &limitations,
|
||||
const Version &clientVersion,
|
||||
bool isWebGL,
|
||||
LinkingVariables *linkingVariables,
|
||||
ProgramLinkedResources *resources,
|
||||
ProgramMergedVaryings *mergedVaryingsOut);
|
||||
|
||||
void makeNewExecutable(const Context *context);
|
||||
|
||||
bool linkValidateShaders(const Context *context);
|
||||
bool linkValidateShaders();
|
||||
void linkShaders();
|
||||
bool linkAttributes(const Caps &caps, const Limitations &limitations, bool webglCompatibility);
|
||||
bool linkVaryings();
|
||||
|
||||
@@ -615,6 +615,8 @@ void Shader::resolveCompile(const Context *context)
|
||||
bool success = mCompilingState->compileEvent->postTranslate(&mInfoLog);
|
||||
mState.mCompileStatus = success ? CompileStatus::COMPILED : CompileStatus::NOT_COMPILED;
|
||||
|
||||
mState.mCompiledState->successfullyCompiled = success;
|
||||
|
||||
MemoryShaderCache *shaderCache = context->getMemoryShaderCache();
|
||||
if (success && shaderCache)
|
||||
{
|
||||
@@ -772,7 +774,8 @@ angle::Result Shader::loadBinaryImpl(const Context *context,
|
||||
|
||||
// Only successfully-compiled shaders are serialized. If deserialization is successful, we can
|
||||
// assume the CompileStatus.
|
||||
mState.mCompileStatus = CompileStatus::COMPILED;
|
||||
mState.mCompileStatus = CompileStatus::COMPILED;
|
||||
mState.mCompiledState->successfullyCompiled = true;
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,22 @@
|
||||
|
||||
namespace rx
|
||||
{
|
||||
std::vector<std::shared_ptr<LinkSubTask>> LinkTask::link(
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings)
|
||||
{
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
std::vector<std::shared_ptr<LinkSubTask>> LinkTask::load()
|
||||
{
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
bool LinkTask::isLinkingInternally()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
angle::Result ProgramImpl::onLabelUpdate(const gl::Context *context)
|
||||
{
|
||||
|
||||
@@ -10,11 +10,13 @@
|
||||
#define LIBANGLE_RENDERER_PROGRAMIMPL_H_
|
||||
|
||||
#include "common/BinaryStream.h"
|
||||
#include "common/WorkerThread.h"
|
||||
#include "common/angleutils.h"
|
||||
#include "libANGLE/Constants.h"
|
||||
#include "libANGLE/Program.h"
|
||||
#include "libANGLE/Shader.h"
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
namespace gl
|
||||
@@ -30,44 +32,47 @@ struct BlockMemberInfo;
|
||||
|
||||
namespace rx
|
||||
{
|
||||
|
||||
// Provides a mechanism to access the result of asynchronous linking.
|
||||
class LinkEvent : angle::NonCopyable
|
||||
// The link job is split as such:
|
||||
//
|
||||
// - Front-end link
|
||||
// - Back-end link
|
||||
// - Independent back-end link subtasks (typically native driver compile jobs)
|
||||
// - Post-link finalization
|
||||
//
|
||||
// Each step depends on the previous. These steps are executed as such:
|
||||
//
|
||||
// 1. Program::link calls into ProgramImpl::link
|
||||
// - ProgramImpl::link runs whatever needs the Context, such as releasing resources
|
||||
// - ProgramImpl::link returns a LinkTask
|
||||
// 2. Program::link implements a closure that calls the front-end link and passes the results to
|
||||
// the backend's LinkTask.
|
||||
// 3. The LinkTask potentially returns a set of LinkSubTasks to be scheduled by the worker pool
|
||||
// 4. Once the link is resolved, the post-link finalization is run
|
||||
//
|
||||
// In the above, steps 1 and 4 are done under the share group lock. Steps 2 and 3 can be done in
|
||||
// threads or without holding the share group lock if the backend supports it.
|
||||
class LinkSubTask : public angle::Closure
|
||||
{
|
||||
public:
|
||||
virtual ~LinkEvent() {}
|
||||
|
||||
// Please be aware that these methods may be called under a gl::Context other
|
||||
// than the one where the LinkEvent was created.
|
||||
//
|
||||
// Waits until the linking is actually done. Returns true if the linking
|
||||
// succeeded, false otherwise.
|
||||
virtual angle::Result wait(const gl::Context *context) = 0;
|
||||
// Peeks whether the linking is still ongoing.
|
||||
virtual bool isLinking() = 0;
|
||||
~LinkSubTask() override = default;
|
||||
virtual angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) = 0;
|
||||
};
|
||||
|
||||
// Wraps an already done linking.
|
||||
class LinkEventDone final : public LinkEvent
|
||||
class LinkTask
|
||||
{
|
||||
public:
|
||||
LinkEventDone(angle::Result result) : mResult(result) {}
|
||||
angle::Result wait(const gl::Context *context) override;
|
||||
bool isLinking() override;
|
||||
virtual ~LinkTask() = default;
|
||||
// Used for link()
|
||||
virtual std::vector<std::shared_ptr<LinkSubTask>> link(
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings);
|
||||
// Used for load()
|
||||
virtual std::vector<std::shared_ptr<LinkSubTask>> load();
|
||||
virtual angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) = 0;
|
||||
|
||||
private:
|
||||
angle::Result mResult;
|
||||
// Used by the GL backend to query whether the driver is linking in parallel internally.
|
||||
virtual bool isLinkingInternally();
|
||||
};
|
||||
|
||||
inline angle::Result LinkEventDone::wait(const gl::Context *context)
|
||||
{
|
||||
return mResult;
|
||||
}
|
||||
inline bool LinkEventDone::isLinking()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
class ProgramImpl : angle::NonCopyable
|
||||
{
|
||||
public:
|
||||
@@ -75,17 +80,17 @@ class ProgramImpl : angle::NonCopyable
|
||||
virtual ~ProgramImpl() {}
|
||||
virtual void destroy(const gl::Context *context) {}
|
||||
|
||||
virtual std::unique_ptr<LinkEvent> load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream) = 0;
|
||||
virtual angle::Result load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream,
|
||||
std::shared_ptr<LinkTask> *loadTaskOut) = 0;
|
||||
virtual void save(const gl::Context *context, gl::BinaryOutputStream *stream) = 0;
|
||||
virtual void setBinaryRetrievableHint(bool retrievable) = 0;
|
||||
virtual void setSeparable(bool separable) = 0;
|
||||
|
||||
virtual void prepareForLink(const gl::ShaderMap<ShaderImpl *> &shaders) {}
|
||||
virtual std::unique_ptr<LinkEvent> link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::ProgramMergedVaryings &&mergedVaryings) = 0;
|
||||
virtual GLboolean validate(const gl::Caps &caps) = 0;
|
||||
virtual angle::Result link(const gl::Context *context,
|
||||
std::shared_ptr<LinkTask> *linkTaskOut) = 0;
|
||||
virtual GLboolean validate(const gl::Caps &caps) = 0;
|
||||
|
||||
virtual void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) = 0;
|
||||
virtual void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) = 0;
|
||||
|
||||
@@ -92,6 +92,86 @@ class HLSLBlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory
|
||||
return new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
|
||||
}
|
||||
};
|
||||
|
||||
// GetExecutableTask class
|
||||
class GetExecutableTask : public LinkSubTask, public d3d::Context
|
||||
{
|
||||
public:
|
||||
GetExecutableTask(ProgramD3D *program, const SharedCompiledShaderStateD3D &shader)
|
||||
: mProgram(program), mExecutable(program->getExecutable()), mShader(shader)
|
||||
{}
|
||||
~GetExecutableTask() override = default;
|
||||
|
||||
angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
|
||||
{
|
||||
ASSERT((mResult == angle::Result::Continue) == (mStoredHR == S_OK));
|
||||
|
||||
ANGLE_TRY(checkTask(context, infoLog));
|
||||
|
||||
// Append debug info
|
||||
if (mShader)
|
||||
{
|
||||
mShader->appendDebugInfo(mShaderExecutable->getDebugInfo());
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
void handleResult(HRESULT hr,
|
||||
const char *message,
|
||||
const char *file,
|
||||
const char *function,
|
||||
unsigned int line) override
|
||||
{
|
||||
mStoredHR = hr;
|
||||
mStoredMessage = message;
|
||||
mStoredFile = file;
|
||||
mStoredFunction = function;
|
||||
mStoredLine = line;
|
||||
}
|
||||
|
||||
protected:
|
||||
void popError(d3d::Context *context)
|
||||
{
|
||||
ASSERT(mStoredFile);
|
||||
ASSERT(mStoredFunction);
|
||||
context->handleResult(mStoredHR, mStoredMessage.c_str(), mStoredFile, mStoredFunction,
|
||||
mStoredLine);
|
||||
}
|
||||
|
||||
angle::Result checkTask(const gl::Context *context, gl::InfoLog &infoLog)
|
||||
{
|
||||
// Forward any logs
|
||||
if (!mInfoLog.empty())
|
||||
{
|
||||
infoLog << mInfoLog.str();
|
||||
}
|
||||
|
||||
// Forward any errors
|
||||
if (mResult != angle::Result::Continue)
|
||||
{
|
||||
ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
|
||||
popError(contextD3D);
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
ProgramD3D *mProgram = nullptr;
|
||||
ProgramExecutableD3D *mExecutable = nullptr;
|
||||
angle::Result mResult = angle::Result::Continue;
|
||||
gl::InfoLog mInfoLog;
|
||||
ShaderExecutableD3D *mShaderExecutable = nullptr;
|
||||
SharedCompiledShaderStateD3D mShader;
|
||||
|
||||
// Error handling
|
||||
HRESULT mStoredHR = S_OK;
|
||||
std::string mStoredMessage;
|
||||
const char *mStoredFile = nullptr;
|
||||
const char *mStoredFunction = nullptr;
|
||||
unsigned int mStoredLine = 0;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
// ProgramD3DMetadata Implementation
|
||||
@@ -256,21 +336,117 @@ uint8_t ProgramD3DMetadata::getCullDistanceArraySize() const
|
||||
return shader ? shader->cullDistanceSize : 0;
|
||||
}
|
||||
|
||||
// ProgramD3D::GetExecutableTask class
|
||||
class ProgramD3D::GetExecutableTask : public Closure, public d3d::Context
|
||||
// ProgramD3D Implementation
|
||||
|
||||
class ProgramD3D::GetVertexExecutableTask : public GetExecutableTask
|
||||
{
|
||||
public:
|
||||
GetExecutableTask(ProgramD3D *program, ProgramExecutableD3D *executable)
|
||||
: mProgram(program), mExecutable(executable)
|
||||
GetVertexExecutableTask(ProgramD3D *program, const SharedCompiledShaderStateD3D &shader)
|
||||
: GetExecutableTask(program, shader)
|
||||
{}
|
||||
~GetVertexExecutableTask() override = default;
|
||||
|
||||
virtual angle::Result run() = 0;
|
||||
void operator()() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "GetVertexExecutableTask::run");
|
||||
|
||||
void operator()() override { mResult = run(); }
|
||||
mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Vertex);
|
||||
mResult = mExecutable->getVertexExecutableForCachedInputLayout(
|
||||
this, mProgram->mRenderer, &mShaderExecutable, &mInfoLog);
|
||||
}
|
||||
};
|
||||
|
||||
angle::Result getResult() const { return mResult; }
|
||||
const gl::InfoLog &getInfoLog() const { return mInfoLog; }
|
||||
ShaderExecutableD3D *getExecutable() { return mShaderExecutable; }
|
||||
class ProgramD3D::GetPixelExecutableTask : public GetExecutableTask
|
||||
{
|
||||
public:
|
||||
GetPixelExecutableTask(ProgramD3D *program, const SharedCompiledShaderStateD3D &shader)
|
||||
: GetExecutableTask(program, shader)
|
||||
{}
|
||||
~GetPixelExecutableTask() override = default;
|
||||
|
||||
void operator()() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "GetPixelExecutableTask::run");
|
||||
if (!mShader)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mExecutable->updateCachedOutputLayoutFromShader();
|
||||
mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Fragment);
|
||||
mResult = mExecutable->getPixelExecutableForCachedOutputLayout(
|
||||
this, mProgram->mRenderer, &mShaderExecutable, &mInfoLog);
|
||||
}
|
||||
};
|
||||
|
||||
class ProgramD3D::GetGeometryExecutableTask : public GetExecutableTask
|
||||
{
|
||||
public:
|
||||
GetGeometryExecutableTask(ProgramD3D *program,
|
||||
const SharedCompiledShaderStateD3D &shader,
|
||||
const gl::Caps &caps,
|
||||
gl::ProvokingVertexConvention provokingVertex)
|
||||
: GetExecutableTask(program, shader), mCaps(caps), mProvokingVertex(provokingVertex)
|
||||
{}
|
||||
~GetGeometryExecutableTask() override = default;
|
||||
|
||||
void operator()() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "GetGeometryExecutableTask::run");
|
||||
// Auto-generate the geometry shader here, if we expect to be using point rendering in
|
||||
// D3D11.
|
||||
if (mExecutable->usesGeometryShader(mProgram->mRenderer, mProvokingVertex,
|
||||
gl::PrimitiveMode::Points))
|
||||
{
|
||||
mResult = mExecutable->getGeometryExecutableForPrimitiveType(
|
||||
this, mProgram->mRenderer, mCaps, mProvokingVertex, gl::PrimitiveMode::Points,
|
||||
&mShaderExecutable, &mInfoLog);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const gl::Caps &mCaps;
|
||||
gl::ProvokingVertexConvention mProvokingVertex;
|
||||
};
|
||||
|
||||
class ProgramD3D::GetComputeExecutableTask : public GetExecutableTask
|
||||
{
|
||||
public:
|
||||
GetComputeExecutableTask(ProgramD3D *program, const SharedCompiledShaderStateD3D &shader)
|
||||
: GetExecutableTask(program, shader)
|
||||
{}
|
||||
~GetComputeExecutableTask() override = default;
|
||||
|
||||
void operator()() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "GetComputeExecutableTask::run");
|
||||
|
||||
mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Compute);
|
||||
mResult = mExecutable->getComputeExecutableForImage2DBindLayout(
|
||||
this, mProgram->mRenderer, &mShaderExecutable, &mInfoLog);
|
||||
}
|
||||
};
|
||||
|
||||
class ProgramD3D::LinkLoadTaskD3D : public d3d::Context, public LinkTask
|
||||
{
|
||||
public:
|
||||
LinkLoadTaskD3D(ProgramD3D *program) : mProgram(program), mExecutable(program->getExecutable())
|
||||
{
|
||||
ASSERT(mProgram);
|
||||
}
|
||||
~LinkLoadTaskD3D() override = default;
|
||||
|
||||
angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
|
||||
{
|
||||
if (mStoredHR != S_OK)
|
||||
{
|
||||
GetImplAs<ContextD3D>(context)->handleResult(mStoredHR, mStoredMessage.c_str(),
|
||||
mStoredFile, mStoredFunction, mStoredLine);
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
void handleResult(HRESULT hr,
|
||||
const char *message,
|
||||
@@ -285,28 +461,115 @@ class ProgramD3D::GetExecutableTask : public Closure, public d3d::Context
|
||||
mStoredLine = line;
|
||||
}
|
||||
|
||||
void popError(d3d::Context *context)
|
||||
{
|
||||
ASSERT(mStoredFile);
|
||||
ASSERT(mStoredFunction);
|
||||
context->handleResult(mStoredHR, mStoredMessage.c_str(), mStoredFile, mStoredFunction,
|
||||
mStoredLine);
|
||||
}
|
||||
|
||||
protected:
|
||||
ProgramD3D *mProgram = nullptr;
|
||||
// The front-end ensures that the program is not accessed while linking, so it is safe to
|
||||
// direclty access the state from a potentially parallel job.
|
||||
ProgramD3D *mProgram;
|
||||
ProgramExecutableD3D *mExecutable = nullptr;
|
||||
angle::Result mResult = angle::Result::Continue;
|
||||
gl::InfoLog mInfoLog;
|
||||
ShaderExecutableD3D *mShaderExecutable = nullptr;
|
||||
HRESULT mStoredHR = S_OK;
|
||||
|
||||
// Error handling
|
||||
HRESULT mStoredHR = S_OK;
|
||||
std::string mStoredMessage;
|
||||
const char *mStoredFile = nullptr;
|
||||
const char *mStoredFunction = nullptr;
|
||||
unsigned int mStoredLine = 0;
|
||||
};
|
||||
|
||||
// ProgramD3D Implementation
|
||||
class ProgramD3D::LinkTaskD3D final : public LinkLoadTaskD3D
|
||||
{
|
||||
public:
|
||||
LinkTaskD3D(const gl::Version &clientVersion,
|
||||
const gl::Caps &caps,
|
||||
EGLenum clientType,
|
||||
ProgramD3D *program,
|
||||
gl::ProvokingVertexConvention provokingVertex)
|
||||
: LinkLoadTaskD3D(program),
|
||||
mClientVersion(clientVersion),
|
||||
mCaps(caps),
|
||||
mClientType(clientType),
|
||||
mProvokingVertex(provokingVertex)
|
||||
{}
|
||||
~LinkTaskD3D() override = default;
|
||||
|
||||
std::vector<std::shared_ptr<LinkSubTask>> link(
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings) override;
|
||||
|
||||
private:
|
||||
const gl::Version mClientVersion;
|
||||
const gl::Caps &mCaps;
|
||||
const EGLenum mClientType;
|
||||
const gl::ProvokingVertexConvention mProvokingVertex;
|
||||
};
|
||||
|
||||
std::vector<std::shared_ptr<LinkSubTask>> ProgramD3D::LinkTaskD3D::link(
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "LinkTaskD3D::link");
|
||||
|
||||
angle::Result result =
|
||||
mProgram->linkJobImpl(this, mCaps, mClientVersion, mClientType, resources, mergedVaryings);
|
||||
ASSERT((result == angle::Result::Continue) == (mStoredHR == S_OK));
|
||||
|
||||
if (result != angle::Result::Continue)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
// Create the subtasks
|
||||
std::vector<std::shared_ptr<LinkSubTask>> subTasks;
|
||||
|
||||
if (mExecutable->hasShaderStage(gl::ShaderType::Compute))
|
||||
{
|
||||
subTasks.push_back(std::make_shared<GetComputeExecutableTask>(
|
||||
mProgram, mProgram->getAttachedShader(gl::ShaderType::Compute)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Geometry shaders are currently only used internally, so there is no corresponding shader
|
||||
// object at the interface level. For now the geometry shader debug info is prepended to the
|
||||
// vertex shader.
|
||||
subTasks.push_back(std::make_shared<GetVertexExecutableTask>(
|
||||
mProgram, mProgram->getAttachedShader(gl::ShaderType::Vertex)));
|
||||
subTasks.push_back(std::make_shared<GetPixelExecutableTask>(
|
||||
mProgram, mProgram->getAttachedShader(gl::ShaderType::Fragment)));
|
||||
subTasks.push_back(std::make_shared<GetGeometryExecutableTask>(
|
||||
mProgram, mProgram->getAttachedShader(gl::ShaderType::Vertex), mCaps,
|
||||
mProvokingVertex));
|
||||
}
|
||||
|
||||
return subTasks;
|
||||
}
|
||||
|
||||
class ProgramD3D::LoadTaskD3D final : public LinkLoadTaskD3D
|
||||
{
|
||||
public:
|
||||
LoadTaskD3D(ProgramD3D *program, angle::MemoryBuffer &&streamData)
|
||||
: LinkLoadTaskD3D(program), mStreamData(std::move(streamData))
|
||||
{}
|
||||
~LoadTaskD3D() override = default;
|
||||
|
||||
std::vector<std::shared_ptr<LinkSubTask>> load() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "LoadTaskD3D::load");
|
||||
|
||||
gl::BinaryInputStream stream(mStreamData.data(), mStreamData.size());
|
||||
mResult = mExecutable->loadBinaryShaderExecutables(this, mProgram->mRenderer, &stream);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
|
||||
{
|
||||
ANGLE_TRY(LinkLoadTaskD3D::getResult(context, infoLog));
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private:
|
||||
angle::MemoryBuffer mStreamData;
|
||||
angle::Result mResult = angle::Result::Continue;
|
||||
};
|
||||
|
||||
ProgramD3D::ProgramD3D(const gl::ProgramState &state, RendererD3D *renderer)
|
||||
: ProgramImpl(state), mRenderer(renderer)
|
||||
@@ -316,96 +579,35 @@ ProgramD3D::~ProgramD3D() = default;
|
||||
|
||||
void ProgramD3D::destroy(const gl::Context *context)
|
||||
{
|
||||
reset();
|
||||
getExecutable()->reset();
|
||||
}
|
||||
|
||||
class ProgramD3D::LoadBinaryTask : public ProgramD3D::GetExecutableTask
|
||||
{
|
||||
public:
|
||||
LoadBinaryTask(ProgramD3D *program,
|
||||
ProgramExecutableD3D *executable,
|
||||
gl::BinaryInputStream *stream,
|
||||
gl::InfoLog &infoLog)
|
||||
: ProgramD3D::GetExecutableTask(program, executable)
|
||||
{
|
||||
ASSERT(mProgram);
|
||||
ASSERT(mExecutable);
|
||||
ASSERT(stream);
|
||||
|
||||
// Copy the remaining data from the stream locally so that the client can't modify it when
|
||||
// loading off thread.
|
||||
size_t dataSize = stream->remainingSize();
|
||||
mDataCopySucceeded = mStreamData.resize(dataSize);
|
||||
if (mDataCopySucceeded)
|
||||
{
|
||||
memcpy(mStreamData.data(), stream->data() + stream->offset(), dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
angle::Result run() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::LoadBinaryTask::run");
|
||||
if (!mDataCopySucceeded)
|
||||
{
|
||||
mInfoLog << "Failed to copy program binary data to local buffer.";
|
||||
return angle::Result::Incomplete;
|
||||
}
|
||||
|
||||
gl::BinaryInputStream stream(mStreamData.data(), mStreamData.size());
|
||||
return mExecutable->loadBinaryShaderExecutables(this, mProgram->mRenderer, &stream,
|
||||
mInfoLog);
|
||||
}
|
||||
|
||||
private:
|
||||
bool mDataCopySucceeded;
|
||||
angle::MemoryBuffer mStreamData;
|
||||
};
|
||||
|
||||
class ProgramD3D::LoadBinaryLinkEvent final : public LinkEvent
|
||||
{
|
||||
public:
|
||||
LoadBinaryLinkEvent(std::shared_ptr<WorkerThreadPool> workerPool,
|
||||
ProgramD3D *program,
|
||||
ProgramExecutableD3D *executable,
|
||||
gl::BinaryInputStream *stream,
|
||||
gl::InfoLog &infoLog)
|
||||
: mTask(std::make_shared<ProgramD3D::LoadBinaryTask>(program, executable, stream, infoLog)),
|
||||
mWaitableEvent(workerPool->postWorkerTask(mTask))
|
||||
{}
|
||||
|
||||
angle::Result wait(const gl::Context *context) override
|
||||
{
|
||||
mWaitableEvent->wait();
|
||||
|
||||
// Continue and Incomplete are not errors. For Stop, pass the error to the ContextD3D.
|
||||
if (mTask->getResult() != angle::Result::Stop)
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
|
||||
mTask->popError(contextD3D);
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
bool isLinking() override { return !mWaitableEvent->isReady(); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<ProgramD3D::LoadBinaryTask> mTask;
|
||||
std::shared_ptr<WaitableEvent> mWaitableEvent;
|
||||
};
|
||||
|
||||
std::unique_ptr<rx::LinkEvent> ProgramD3D::load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream)
|
||||
angle::Result ProgramD3D::load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream,
|
||||
std::shared_ptr<LinkTask> *loadTaskOut)
|
||||
{
|
||||
if (!getExecutable()->load(context, mRenderer, stream))
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(angle::Result::Stop);
|
||||
mState.getExecutable().getInfoLog()
|
||||
<< "Invalid program binary, device configuration has changed.";
|
||||
return angle::Result::Incomplete;
|
||||
}
|
||||
|
||||
return std::make_unique<LoadBinaryLinkEvent>(context->getShaderCompileThreadPool(), this,
|
||||
getExecutable(), stream,
|
||||
mState.getExecutable().getInfoLog());
|
||||
// Copy the remaining data from the stream locally so that the client can't modify it when
|
||||
// loading off thread.
|
||||
angle::MemoryBuffer streamData;
|
||||
const size_t dataSize = stream->remainingSize();
|
||||
if (!streamData.resize(dataSize))
|
||||
{
|
||||
mState.getExecutable().getInfoLog()
|
||||
<< "Failed to copy program binary data to local buffer.";
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
memcpy(streamData.data(), stream->data() + stream->offset(), dataSize);
|
||||
|
||||
// Note: pretty much all the above can also be moved to the task
|
||||
*loadTaskOut = std::shared_ptr<LinkTask>(new LoadTaskD3D(this, std::move(streamData)));
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream)
|
||||
@@ -417,277 +619,6 @@ void ProgramD3D::setBinaryRetrievableHint(bool /* retrievable */) {}
|
||||
|
||||
void ProgramD3D::setSeparable(bool /* separable */) {}
|
||||
|
||||
class ProgramD3D::GetVertexExecutableTask : public ProgramD3D::GetExecutableTask
|
||||
{
|
||||
public:
|
||||
GetVertexExecutableTask(ProgramD3D *program, ProgramExecutableD3D *executable)
|
||||
: GetExecutableTask(program, executable)
|
||||
{}
|
||||
angle::Result run() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::GetVertexExecutableTask::run");
|
||||
|
||||
mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Vertex);
|
||||
ANGLE_TRY(mExecutable->getVertexExecutableForCachedInputLayout(
|
||||
this, mProgram->mRenderer, &mShaderExecutable, &mInfoLog));
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
};
|
||||
|
||||
class ProgramD3D::GetPixelExecutableTask : public ProgramD3D::GetExecutableTask
|
||||
{
|
||||
public:
|
||||
GetPixelExecutableTask(ProgramD3D *program, ProgramExecutableD3D *executable)
|
||||
: GetExecutableTask(program, executable)
|
||||
{}
|
||||
angle::Result run() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::GetPixelExecutableTask::run");
|
||||
if (!mProgram->mState.getAttachedShader(gl::ShaderType::Fragment))
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
mExecutable->updateCachedOutputLayoutFromShader();
|
||||
mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Fragment);
|
||||
ANGLE_TRY(mExecutable->getPixelExecutableForCachedOutputLayout(
|
||||
this, mProgram->mRenderer, &mShaderExecutable, &mInfoLog));
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
};
|
||||
|
||||
class ProgramD3D::GetGeometryExecutableTask : public ProgramD3D::GetExecutableTask
|
||||
{
|
||||
public:
|
||||
GetGeometryExecutableTask(ProgramD3D *program,
|
||||
ProgramExecutableD3D *executable,
|
||||
const gl::Caps &caps,
|
||||
gl::ProvokingVertexConvention provokingVertex)
|
||||
: GetExecutableTask(program, executable), mCaps(caps), mProvokingVertex(provokingVertex)
|
||||
{}
|
||||
|
||||
angle::Result run() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::GetGeometryExecutableTask::run");
|
||||
// Auto-generate the geometry shader here, if we expect to be using point rendering in
|
||||
// D3D11.
|
||||
if (mExecutable->usesGeometryShader(mProgram->mRenderer, mProvokingVertex,
|
||||
gl::PrimitiveMode::Points))
|
||||
{
|
||||
ANGLE_TRY(mExecutable->getGeometryExecutableForPrimitiveType(
|
||||
this, mProgram->mRenderer, mCaps, mProvokingVertex, gl::PrimitiveMode::Points,
|
||||
&mShaderExecutable, &mInfoLog));
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
private:
|
||||
const gl::Caps &mCaps;
|
||||
gl::ProvokingVertexConvention mProvokingVertex;
|
||||
};
|
||||
|
||||
class ProgramD3D::GetComputeExecutableTask : public ProgramD3D::GetExecutableTask
|
||||
{
|
||||
public:
|
||||
GetComputeExecutableTask(ProgramD3D *program, ProgramExecutableD3D *executable)
|
||||
: GetExecutableTask(program, executable)
|
||||
{}
|
||||
angle::Result run() override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::GetComputeExecutableTask::run");
|
||||
mExecutable->updateCachedImage2DBindLayoutFromShader(gl::ShaderType::Compute);
|
||||
ShaderExecutableD3D *computeExecutable = nullptr;
|
||||
ANGLE_TRY(mExecutable->getComputeExecutableForImage2DBindLayout(
|
||||
this, mProgram->mRenderer, &computeExecutable, &mInfoLog));
|
||||
|
||||
return computeExecutable ? angle::Result::Continue : angle::Result::Incomplete;
|
||||
}
|
||||
};
|
||||
|
||||
// The LinkEvent implementation for linking a rendering(VS, FS, GS) program.
|
||||
class ProgramD3D::GraphicsProgramLinkEvent final : public LinkEvent
|
||||
{
|
||||
public:
|
||||
GraphicsProgramLinkEvent(gl::InfoLog &infoLog,
|
||||
std::shared_ptr<WorkerThreadPool> workerPool,
|
||||
std::shared_ptr<ProgramD3D::GetVertexExecutableTask> vertexTask,
|
||||
std::shared_ptr<ProgramD3D::GetPixelExecutableTask> pixelTask,
|
||||
std::shared_ptr<ProgramD3D::GetGeometryExecutableTask> geometryTask,
|
||||
bool useGS,
|
||||
const SharedCompiledShaderStateD3D &vertexShader,
|
||||
const SharedCompiledShaderStateD3D &fragmentShader)
|
||||
: mInfoLog(infoLog),
|
||||
mVertexTask(vertexTask),
|
||||
mPixelTask(pixelTask),
|
||||
mGeometryTask(geometryTask),
|
||||
mWaitEvents(
|
||||
{{std::shared_ptr<WaitableEvent>(workerPool->postWorkerTask(mVertexTask)),
|
||||
std::shared_ptr<WaitableEvent>(workerPool->postWorkerTask(mPixelTask)),
|
||||
std::shared_ptr<WaitableEvent>(workerPool->postWorkerTask(mGeometryTask))}}),
|
||||
mUseGS(useGS),
|
||||
mVertexShader(vertexShader),
|
||||
mFragmentShader(fragmentShader)
|
||||
{}
|
||||
|
||||
angle::Result wait(const gl::Context *context) override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::GraphicsProgramLinkEvent::wait");
|
||||
WaitableEvent::WaitMany(&mWaitEvents);
|
||||
|
||||
ANGLE_TRY(checkTask(context, mVertexTask.get()));
|
||||
ANGLE_TRY(checkTask(context, mPixelTask.get()));
|
||||
ANGLE_TRY(checkTask(context, mGeometryTask.get()));
|
||||
|
||||
if (mVertexTask->getResult() == angle::Result::Incomplete ||
|
||||
mPixelTask->getResult() == angle::Result::Incomplete ||
|
||||
mGeometryTask->getResult() == angle::Result::Incomplete)
|
||||
{
|
||||
return angle::Result::Incomplete;
|
||||
}
|
||||
|
||||
ShaderExecutableD3D *defaultVertexExecutable = mVertexTask->getExecutable();
|
||||
ShaderExecutableD3D *defaultPixelExecutable = mPixelTask->getExecutable();
|
||||
ShaderExecutableD3D *pointGS = mGeometryTask->getExecutable();
|
||||
|
||||
if (mUseGS && pointGS)
|
||||
{
|
||||
// Geometry shaders are currently only used internally, so there is no corresponding
|
||||
// shader object at the interface level. For now the geometry shader debug info is
|
||||
// prepended to the vertex shader.
|
||||
mVertexShader->appendDebugInfo("// GEOMETRY SHADER BEGIN\n\n");
|
||||
mVertexShader->appendDebugInfo(pointGS->getDebugInfo());
|
||||
mVertexShader->appendDebugInfo("\nGEOMETRY SHADER END\n\n\n");
|
||||
}
|
||||
|
||||
if (defaultVertexExecutable)
|
||||
{
|
||||
mVertexShader->appendDebugInfo(defaultVertexExecutable->getDebugInfo());
|
||||
}
|
||||
|
||||
if (defaultPixelExecutable)
|
||||
{
|
||||
mFragmentShader->appendDebugInfo(defaultPixelExecutable->getDebugInfo());
|
||||
}
|
||||
|
||||
bool isLinked = (defaultVertexExecutable && defaultPixelExecutable && (!mUseGS || pointGS));
|
||||
if (!isLinked)
|
||||
{
|
||||
mInfoLog << "Failed to create D3D Shaders";
|
||||
}
|
||||
return isLinked ? angle::Result::Continue : angle::Result::Incomplete;
|
||||
}
|
||||
|
||||
bool isLinking() override { return !WaitableEvent::AllReady(&mWaitEvents); }
|
||||
|
||||
private:
|
||||
angle::Result checkTask(const gl::Context *context, ProgramD3D::GetExecutableTask *task)
|
||||
{
|
||||
if (!task->getInfoLog().empty())
|
||||
{
|
||||
mInfoLog << task->getInfoLog().str();
|
||||
}
|
||||
|
||||
// Continue and Incomplete are not errors. For Stop, pass the error to the ContextD3D.
|
||||
if (task->getResult() != angle::Result::Stop)
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
|
||||
task->popError(contextD3D);
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
gl::InfoLog &mInfoLog;
|
||||
std::shared_ptr<ProgramD3D::GetVertexExecutableTask> mVertexTask;
|
||||
std::shared_ptr<ProgramD3D::GetPixelExecutableTask> mPixelTask;
|
||||
std::shared_ptr<ProgramD3D::GetGeometryExecutableTask> mGeometryTask;
|
||||
std::array<std::shared_ptr<WaitableEvent>, 3> mWaitEvents;
|
||||
bool mUseGS;
|
||||
SharedCompiledShaderStateD3D mVertexShader;
|
||||
SharedCompiledShaderStateD3D mFragmentShader;
|
||||
};
|
||||
|
||||
// The LinkEvent implementation for linking a computing program.
|
||||
class ProgramD3D::ComputeProgramLinkEvent final : public LinkEvent
|
||||
{
|
||||
public:
|
||||
ComputeProgramLinkEvent(gl::InfoLog &infoLog,
|
||||
std::shared_ptr<ProgramD3D::GetComputeExecutableTask> computeTask,
|
||||
std::shared_ptr<WaitableEvent> event)
|
||||
: mInfoLog(infoLog), mComputeTask(computeTask), mWaitEvent(event)
|
||||
{}
|
||||
|
||||
bool isLinking() override { return !mWaitEvent->isReady(); }
|
||||
|
||||
angle::Result wait(const gl::Context *context) override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::ComputeProgramLinkEvent::wait");
|
||||
mWaitEvent->wait();
|
||||
|
||||
angle::Result result = mComputeTask->getResult();
|
||||
if (result != angle::Result::Continue)
|
||||
{
|
||||
mInfoLog << "Failed to create D3D compute shader.";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
gl::InfoLog &mInfoLog;
|
||||
std::shared_ptr<ProgramD3D::GetComputeExecutableTask> mComputeTask;
|
||||
std::shared_ptr<WaitableEvent> mWaitEvent;
|
||||
};
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramD3D::compileProgramExecutables(const gl::Context *context)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::compileProgramExecutables");
|
||||
|
||||
ProgramExecutableD3D *executableD3D = getExecutable();
|
||||
|
||||
auto vertexTask = std::make_shared<GetVertexExecutableTask>(this, executableD3D);
|
||||
auto pixelTask = std::make_shared<GetPixelExecutableTask>(this, executableD3D);
|
||||
auto geometryTask = std::make_shared<GetGeometryExecutableTask>(
|
||||
this, executableD3D, context->getCaps(), context->getState().getProvokingVertex());
|
||||
bool useGS = executableD3D->usesGeometryShader(
|
||||
mRenderer, context->getState().getProvokingVertex(), gl::PrimitiveMode::Points);
|
||||
const SharedCompiledShaderStateD3D &vertexShaderD3D =
|
||||
executableD3D->mAttachedShaders[gl::ShaderType::Vertex];
|
||||
const SharedCompiledShaderStateD3D &fragmentShaderD3D =
|
||||
executableD3D->mAttachedShaders[gl::ShaderType::Fragment];
|
||||
|
||||
return std::make_unique<GraphicsProgramLinkEvent>(
|
||||
mState.getExecutable().getInfoLog(), context->getShaderCompileThreadPool(), vertexTask,
|
||||
pixelTask, geometryTask, useGS, vertexShaderD3D, fragmentShaderD3D);
|
||||
}
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramD3D::compileComputeExecutable(const gl::Context *context)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::compileComputeExecutable");
|
||||
auto computeTask = std::make_shared<GetComputeExecutableTask>(this, getExecutable());
|
||||
|
||||
std::shared_ptr<WaitableEvent> waitableEvent;
|
||||
|
||||
// TODO(jie.a.chen@intel.com): Fix the flaky bug.
|
||||
// http://anglebug.com/3349
|
||||
bool compileInParallel = false;
|
||||
if (!compileInParallel)
|
||||
{
|
||||
(*computeTask)();
|
||||
waitableEvent = std::make_shared<WaitableEventDone>();
|
||||
}
|
||||
else
|
||||
{
|
||||
waitableEvent = context->getShaderCompileThreadPool()->postWorkerTask(computeTask);
|
||||
}
|
||||
|
||||
return std::make_unique<ComputeProgramLinkEvent>(mState.getExecutable().getInfoLog(),
|
||||
computeTask, waitableEvent);
|
||||
}
|
||||
|
||||
void ProgramD3D::prepareForLink(const gl::ShaderMap<ShaderImpl *> &shaders)
|
||||
{
|
||||
ProgramExecutableD3D *executableD3D = getExecutable();
|
||||
@@ -704,9 +635,7 @@ void ProgramD3D::prepareForLink(const gl::ShaderMap<ShaderImpl *> &shaders)
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::ProgramMergedVaryings && /*mergedVaryings*/)
|
||||
angle::Result ProgramD3D::link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramD3D::link");
|
||||
const gl::Version &clientVersion = context->getClientVersion();
|
||||
@@ -714,16 +643,10 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
|
||||
EGLenum clientType = context->getClientType();
|
||||
|
||||
// Ensure the compiler is initialized to avoid race conditions.
|
||||
angle::Result result = mRenderer->ensureHLSLCompilerInitialized(GetImplAs<ContextD3D>(context));
|
||||
if (result != angle::Result::Continue)
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(result);
|
||||
}
|
||||
ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized(GetImplAs<ContextD3D>(context)));
|
||||
|
||||
ProgramExecutableD3D *executableD3D = getExecutable();
|
||||
|
||||
reset();
|
||||
|
||||
const gl::SharedCompiledShaderState &computeShader =
|
||||
mState.getAttachedShader(gl::ShaderType::Compute);
|
||||
if (!computeShader)
|
||||
@@ -758,6 +681,23 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
|
||||
}
|
||||
}
|
||||
|
||||
*linkTaskOut = std::shared_ptr<LinkTask>(new LinkTaskD3D(
|
||||
clientVersion, caps, clientType, this, context->getState().getProvokingVertex()));
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result ProgramD3D::linkJobImpl(d3d::Context *context,
|
||||
const gl::Caps &caps,
|
||||
const gl::Version &clientVersion,
|
||||
EGLenum clientType,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings)
|
||||
{
|
||||
ProgramExecutableD3D *executableD3D = getExecutable();
|
||||
|
||||
const gl::SharedCompiledShaderState &computeShader =
|
||||
mState.getAttachedShader(gl::ShaderType::Compute);
|
||||
if (computeShader)
|
||||
{
|
||||
const gl::SharedCompiledShaderState &shader =
|
||||
@@ -783,100 +723,98 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
|
||||
|
||||
executableD3D->defineUniformsAndAssignRegisters(mRenderer, mState.getAttachedShaders());
|
||||
|
||||
return compileComputeExecutable(context);
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
else
|
||||
|
||||
for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
|
||||
{
|
||||
for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
|
||||
const gl::SharedCompiledShaderState &shader = mState.getAttachedShader(shaderType);
|
||||
if (shader)
|
||||
{
|
||||
const gl::SharedCompiledShaderState &shader = mState.getAttachedShader(shaderType);
|
||||
if (shader)
|
||||
executableD3D->mAttachedShaders[shaderType]->generateWorkarounds(
|
||||
&executableD3D->mShaderWorkarounds[shaderType]);
|
||||
executableD3D->mShaderSamplers[shaderType].resize(
|
||||
caps.maxShaderTextureImageUnits[shaderType]);
|
||||
executableD3D->mImages[shaderType].resize(caps.maxImageUnits);
|
||||
executableD3D->mReadonlyImages[shaderType].resize(caps.maxImageUnits);
|
||||
|
||||
executableD3D->mShaderUniformsDirty.set(shaderType);
|
||||
|
||||
for (const sh::ShaderVariable &uniform : shader->uniforms)
|
||||
{
|
||||
executableD3D->mAttachedShaders[shaderType]->generateWorkarounds(
|
||||
&executableD3D->mShaderWorkarounds[shaderType]);
|
||||
executableD3D->mShaderSamplers[shaderType].resize(
|
||||
caps.maxShaderTextureImageUnits[shaderType]);
|
||||
executableD3D->mImages[shaderType].resize(caps.maxImageUnits);
|
||||
executableD3D->mReadonlyImages[shaderType].resize(caps.maxImageUnits);
|
||||
|
||||
executableD3D->mShaderUniformsDirty.set(shaderType);
|
||||
|
||||
for (const sh::ShaderVariable &uniform : shader->uniforms)
|
||||
if (gl::IsImageType(uniform.type) && gl::IsImage2DType(uniform.type))
|
||||
{
|
||||
if (gl::IsImageType(uniform.type) && gl::IsImage2DType(uniform.type))
|
||||
{
|
||||
executableD3D->mImage2DUniforms[shaderType].push_back(uniform);
|
||||
}
|
||||
executableD3D->mImage2DUniforms[shaderType].push_back(uniform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mRenderer->getNativeLimitations().noFrontFacingSupport)
|
||||
{
|
||||
const SharedCompiledShaderStateD3D &fragmentShader =
|
||||
executableD3D->mAttachedShaders[gl::ShaderType::Fragment];
|
||||
if (fragmentShader && fragmentShader->usesFrontFacing)
|
||||
{
|
||||
mState.getExecutable().getInfoLog()
|
||||
<< "The current renderer doesn't support gl_FrontFacing";
|
||||
return std::make_unique<LinkEventDone>(angle::Result::Incomplete);
|
||||
}
|
||||
}
|
||||
|
||||
const gl::VaryingPacking &varyingPacking =
|
||||
resources.varyingPacking.getOutputPacking(gl::ShaderType::Vertex);
|
||||
|
||||
ProgramD3DMetadata metadata(
|
||||
mRenderer, mState.getAttachedShader(gl::ShaderType::Fragment),
|
||||
executableD3D->mAttachedShaders, clientType,
|
||||
mState.getAttachedShader(gl::ShaderType::Vertex)->shaderVersion);
|
||||
BuiltinVaryingsD3D builtins(metadata, varyingPacking);
|
||||
|
||||
DynamicHLSL::GenerateShaderLinkHLSL(mRenderer, caps, mState.getAttachedShaders(),
|
||||
executableD3D->mAttachedShaders, metadata,
|
||||
varyingPacking, builtins, &executableD3D->mShaderHLSL);
|
||||
|
||||
executableD3D->mUsesPointSize =
|
||||
executableD3D->mAttachedShaders[gl::ShaderType::Vertex] &&
|
||||
executableD3D->mAttachedShaders[gl::ShaderType::Vertex]->usesPointSize;
|
||||
DynamicHLSL::GetPixelShaderOutputKey(mRenderer, caps, clientVersion, mState, metadata,
|
||||
&executableD3D->mPixelShaderKey);
|
||||
executableD3D->mFragDepthUsage = metadata.getFragDepthUsage();
|
||||
executableD3D->mUsesSampleMask = metadata.usesSampleMask();
|
||||
executableD3D->mUsesVertexID = metadata.usesVertexID();
|
||||
executableD3D->mUsesViewID = metadata.usesViewID();
|
||||
executableD3D->mHasMultiviewEnabled = metadata.hasMultiviewEnabled();
|
||||
|
||||
// Cache if we use flat shading
|
||||
executableD3D->mUsesFlatInterpolation =
|
||||
FindFlatInterpolationVarying(mState.getAttachedShaders());
|
||||
|
||||
if (mRenderer->getMajorShaderModel() >= 4)
|
||||
{
|
||||
executableD3D->mGeometryShaderPreamble = DynamicHLSL::GenerateGeometryShaderPreamble(
|
||||
mRenderer, varyingPacking, builtins, executableD3D->mHasMultiviewEnabled,
|
||||
metadata.canSelectViewInVertexShader());
|
||||
}
|
||||
|
||||
executableD3D->initAttribLocationsToD3DSemantic(
|
||||
mState.getAttachedShader(gl::ShaderType::Vertex));
|
||||
|
||||
executableD3D->defineUniformsAndAssignRegisters(mRenderer, mState.getAttachedShaders());
|
||||
|
||||
executableD3D->gatherTransformFeedbackVaryings(mRenderer, varyingPacking,
|
||||
mState.getTransformFeedbackVaryingNames(),
|
||||
builtins[gl::ShaderType::Vertex]);
|
||||
|
||||
linkResources(resources);
|
||||
|
||||
if (mState.getAttachedShader(gl::ShaderType::Vertex))
|
||||
{
|
||||
executableD3D->updateCachedInputLayoutFromShader(
|
||||
mRenderer, mState.getAttachedShader(gl::ShaderType::Vertex));
|
||||
}
|
||||
|
||||
return compileProgramExecutables(context);
|
||||
}
|
||||
|
||||
if (mRenderer->getNativeLimitations().noFrontFacingSupport)
|
||||
{
|
||||
const SharedCompiledShaderStateD3D &fragmentShader =
|
||||
executableD3D->mAttachedShaders[gl::ShaderType::Fragment];
|
||||
if (fragmentShader && fragmentShader->usesFrontFacing)
|
||||
{
|
||||
mState.getExecutable().getInfoLog()
|
||||
<< "The current renderer doesn't support gl_FrontFacing";
|
||||
// Fail compilation
|
||||
ANGLE_CHECK_HR(context, false, "gl_FrontFacing not supported", E_NOTIMPL);
|
||||
}
|
||||
}
|
||||
|
||||
const gl::VaryingPacking &varyingPacking =
|
||||
resources.varyingPacking.getOutputPacking(gl::ShaderType::Vertex);
|
||||
|
||||
ProgramD3DMetadata metadata(mRenderer, mState.getAttachedShader(gl::ShaderType::Fragment),
|
||||
executableD3D->mAttachedShaders, clientType,
|
||||
mState.getAttachedShader(gl::ShaderType::Vertex)->shaderVersion);
|
||||
BuiltinVaryingsD3D builtins(metadata, varyingPacking);
|
||||
|
||||
DynamicHLSL::GenerateShaderLinkHLSL(mRenderer, caps, mState.getAttachedShaders(),
|
||||
executableD3D->mAttachedShaders, metadata, varyingPacking,
|
||||
builtins, &executableD3D->mShaderHLSL);
|
||||
|
||||
executableD3D->mUsesPointSize =
|
||||
executableD3D->mAttachedShaders[gl::ShaderType::Vertex] &&
|
||||
executableD3D->mAttachedShaders[gl::ShaderType::Vertex]->usesPointSize;
|
||||
DynamicHLSL::GetPixelShaderOutputKey(mRenderer, caps, clientVersion, mState, metadata,
|
||||
&executableD3D->mPixelShaderKey);
|
||||
executableD3D->mFragDepthUsage = metadata.getFragDepthUsage();
|
||||
executableD3D->mUsesSampleMask = metadata.usesSampleMask();
|
||||
executableD3D->mUsesVertexID = metadata.usesVertexID();
|
||||
executableD3D->mUsesViewID = metadata.usesViewID();
|
||||
executableD3D->mHasMultiviewEnabled = metadata.hasMultiviewEnabled();
|
||||
|
||||
// Cache if we use flat shading
|
||||
executableD3D->mUsesFlatInterpolation =
|
||||
FindFlatInterpolationVarying(mState.getAttachedShaders());
|
||||
|
||||
if (mRenderer->getMajorShaderModel() >= 4)
|
||||
{
|
||||
executableD3D->mGeometryShaderPreamble = DynamicHLSL::GenerateGeometryShaderPreamble(
|
||||
mRenderer, varyingPacking, builtins, executableD3D->mHasMultiviewEnabled,
|
||||
metadata.canSelectViewInVertexShader());
|
||||
}
|
||||
|
||||
executableD3D->initAttribLocationsToD3DSemantic(
|
||||
mState.getAttachedShader(gl::ShaderType::Vertex));
|
||||
|
||||
executableD3D->defineUniformsAndAssignRegisters(mRenderer, mState.getAttachedShaders());
|
||||
|
||||
executableD3D->gatherTransformFeedbackVaryings(mRenderer, varyingPacking,
|
||||
mState.getTransformFeedbackVaryingNames(),
|
||||
builtins[gl::ShaderType::Vertex]);
|
||||
|
||||
linkResources(resources);
|
||||
|
||||
if (mState.getAttachedShader(gl::ShaderType::Vertex))
|
||||
{
|
||||
executableD3D->updateCachedInputLayoutFromShader(
|
||||
mRenderer, mState.getAttachedShader(gl::ShaderType::Vertex));
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
GLboolean ProgramD3D::validate(const gl::Caps & /*caps*/)
|
||||
@@ -1124,11 +1062,6 @@ void ProgramD3D::setUniformMatrixfvInternal(GLint location,
|
||||
}
|
||||
}
|
||||
|
||||
void ProgramD3D::reset()
|
||||
{
|
||||
getExecutable()->reset();
|
||||
}
|
||||
|
||||
template <typename DestT>
|
||||
void ProgramD3D::getUniformInternal(GLint location, DestT *dataOut) const
|
||||
{
|
||||
|
||||
@@ -78,16 +78,15 @@ class ProgramD3D : public ProgramImpl
|
||||
|
||||
void destroy(const gl::Context *context) override;
|
||||
|
||||
std::unique_ptr<LinkEvent> load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream) override;
|
||||
angle::Result load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream,
|
||||
std::shared_ptr<LinkTask> *loadTaskOut) override;
|
||||
void save(const gl::Context *context, gl::BinaryOutputStream *stream) override;
|
||||
void setBinaryRetrievableHint(bool retrievable) override;
|
||||
void setSeparable(bool separable) override;
|
||||
|
||||
void prepareForLink(const gl::ShaderMap<ShaderImpl *> &shaders) override;
|
||||
std::unique_ptr<LinkEvent> link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::ProgramMergedVaryings &&mergedVaryings) override;
|
||||
angle::Result link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut) override;
|
||||
GLboolean validate(const gl::Caps &caps) override;
|
||||
|
||||
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
|
||||
@@ -155,17 +154,27 @@ class ProgramD3D : public ProgramImpl
|
||||
}
|
||||
|
||||
private:
|
||||
// These forward-declared tasks are used for multi-thread shader compiles.
|
||||
class GetExecutableTask;
|
||||
class GetVertexExecutableTask;
|
||||
class GetPixelExecutableTask;
|
||||
class GetGeometryExecutableTask;
|
||||
class GetComputeExecutableTask;
|
||||
class GraphicsProgramLinkEvent;
|
||||
class ComputeProgramLinkEvent;
|
||||
class LinkLoadTaskD3D;
|
||||
class LinkTaskD3D;
|
||||
class LoadTaskD3D;
|
||||
|
||||
class LoadBinaryTask;
|
||||
class LoadBinaryLinkEvent;
|
||||
friend class LinkTaskD3D;
|
||||
friend class LoadTaskD3D;
|
||||
|
||||
angle::Result linkJobImpl(d3d::Context *context,
|
||||
const gl::Caps &caps,
|
||||
const gl::Version &clientVersion,
|
||||
EGLenum clientType,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings);
|
||||
const SharedCompiledShaderStateD3D &getAttachedShader(gl::ShaderType shaderType)
|
||||
{
|
||||
return getExecutable()->mAttachedShaders[shaderType];
|
||||
}
|
||||
|
||||
template <typename DestT>
|
||||
void getUniformInternal(GLint location, DestT *dataOut) const;
|
||||
@@ -187,11 +196,6 @@ class ProgramD3D : public ProgramImpl
|
||||
GLboolean transpose,
|
||||
const GLfloat *value);
|
||||
|
||||
std::unique_ptr<LinkEvent> compileProgramExecutables(const gl::Context *context);
|
||||
std::unique_ptr<LinkEvent> compileComputeExecutable(const gl::Context *context);
|
||||
|
||||
void reset();
|
||||
|
||||
void linkResources(const gl::ProgramLinkedResources &resources);
|
||||
|
||||
RendererD3D *mRenderer;
|
||||
|
||||
@@ -416,7 +416,9 @@ ProgramExecutableD3D::ProgramExecutableD3D(const gl::ProgramExecutable *executab
|
||||
mUsedReadonlyImageRange({}),
|
||||
mUsedAtomicCounterRange({}),
|
||||
mSerial(issueSerial())
|
||||
{}
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
ProgramExecutableD3D::~ProgramExecutableD3D() {}
|
||||
|
||||
@@ -706,9 +708,9 @@ bool ProgramExecutableD3D::load(const gl::Context *context,
|
||||
|
||||
angle::Result ProgramExecutableD3D::loadBinaryShaderExecutables(d3d::Context *contextD3D,
|
||||
RendererD3D *renderer,
|
||||
gl::BinaryInputStream *stream,
|
||||
gl::InfoLog &infoLog)
|
||||
gl::BinaryInputStream *stream)
|
||||
{
|
||||
gl::InfoLog &infoLog = mExecutable->getInfoLog();
|
||||
const unsigned char *binary = reinterpret_cast<const unsigned char *>(stream->data());
|
||||
|
||||
bool separateAttribs = mExecutable->getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS;
|
||||
|
||||
@@ -344,8 +344,7 @@ class ProgramExecutableD3D : public ProgramExecutableImpl
|
||||
|
||||
angle::Result loadBinaryShaderExecutables(d3d::Context *contextD3D,
|
||||
RendererD3D *renderer,
|
||||
gl::BinaryInputStream *stream,
|
||||
gl::InfoLog &infoLog);
|
||||
gl::BinaryInputStream *stream);
|
||||
|
||||
unsigned int getSerial() const { return mSerial; }
|
||||
|
||||
|
||||
@@ -91,6 +91,75 @@ std::string GetTransformFeedbackVaryingMappedName(const gl::SharedCompiledShader
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class ProgramGL::LinkTaskGL final : public LinkTask
|
||||
{
|
||||
public:
|
||||
LinkTaskGL(ProgramGL *program,
|
||||
bool hasNativeParallelCompile,
|
||||
const FunctionsGL *functions,
|
||||
const gl::Extensions &extensions,
|
||||
GLuint programID)
|
||||
: mProgram(program),
|
||||
mHasNativeParallelCompile(hasNativeParallelCompile),
|
||||
mFunctions(functions),
|
||||
mExtensions(extensions),
|
||||
mProgramID(programID)
|
||||
{}
|
||||
~LinkTaskGL() override = default;
|
||||
|
||||
std::vector<std::shared_ptr<LinkSubTask>> link(
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings) override
|
||||
{
|
||||
mProgram->linkJobImpl(mExtensions);
|
||||
|
||||
// If there is no native parallel compile, do the post-link right away.
|
||||
if (!mHasNativeParallelCompile)
|
||||
{
|
||||
mResult = mProgram->postLinkJobImpl(resources);
|
||||
}
|
||||
|
||||
// See comment on mResources
|
||||
mResources = &resources;
|
||||
return {};
|
||||
}
|
||||
|
||||
angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "LinkTaskGL::getResult");
|
||||
|
||||
if (mHasNativeParallelCompile)
|
||||
{
|
||||
mResult = mProgram->postLinkJobImpl(*mResources);
|
||||
}
|
||||
|
||||
return mResult;
|
||||
}
|
||||
|
||||
bool isLinkingInternally() override
|
||||
{
|
||||
GLint completionStatus = GL_TRUE;
|
||||
if (mHasNativeParallelCompile)
|
||||
{
|
||||
mFunctions->getProgramiv(mProgramID, GL_COMPLETION_STATUS, &completionStatus);
|
||||
}
|
||||
return completionStatus == GL_FALSE;
|
||||
}
|
||||
|
||||
private:
|
||||
ProgramGL *mProgram;
|
||||
const bool mHasNativeParallelCompile;
|
||||
const FunctionsGL *mFunctions;
|
||||
const gl::Extensions &mExtensions;
|
||||
const GLuint mProgramID;
|
||||
|
||||
angle::Result mResult = angle::Result::Continue;
|
||||
|
||||
// Note: resources are kept alive by the front-end for the entire duration of the link,
|
||||
// including during resolve when getResult() and postLink() are called.
|
||||
const gl::ProgramLinkedResources *mResources = nullptr;
|
||||
};
|
||||
|
||||
ProgramGL::ProgramGL(const gl::ProgramState &data,
|
||||
const FunctionsGL *functions,
|
||||
const angle::FeaturesGL &features,
|
||||
@@ -117,14 +186,13 @@ void ProgramGL::destroy(const gl::Context *context)
|
||||
mProgramID = 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramGL::load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream)
|
||||
angle::Result ProgramGL::load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream,
|
||||
std::shared_ptr<LinkTask> *loadTaskOut)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::load");
|
||||
ProgramExecutableGL *executableGL = getExecutable();
|
||||
|
||||
executableGL->reset();
|
||||
|
||||
// Read the binary format, size and blob
|
||||
GLenum binaryFormat = stream->readInt<GLenum>();
|
||||
GLint binaryLength = stream->readInt<GLint>();
|
||||
@@ -137,13 +205,15 @@ std::unique_ptr<LinkEvent> ProgramGL::load(const gl::Context *context,
|
||||
// Verify that the program linked
|
||||
if (!checkLinkStatus())
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(angle::Result::Stop);
|
||||
return angle::Result::Incomplete;
|
||||
}
|
||||
|
||||
executableGL->postLink(mFunctions, mFeatures, mProgramID);
|
||||
reapplyUBOBindingsIfNeeded(context);
|
||||
|
||||
return std::make_unique<LinkEventDone>(angle::Result::Continue);
|
||||
*loadTaskOut = {};
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
void ProgramGL::save(const gl::Context *context, gl::BinaryOutputStream *stream)
|
||||
@@ -192,44 +262,6 @@ void ProgramGL::setSeparable(bool separable)
|
||||
mFunctions->programParameteri(mProgramID, GL_PROGRAM_SEPARABLE, separable ? GL_TRUE : GL_FALSE);
|
||||
}
|
||||
|
||||
using PostLinkImplFunctor = std::function<angle::Result()>;
|
||||
|
||||
// The event for a parallelized linking using the native driver extension.
|
||||
class ProgramGL::LinkEventNativeParallel final : public LinkEvent
|
||||
{
|
||||
public:
|
||||
LinkEventNativeParallel(PostLinkImplFunctor &&functor,
|
||||
const FunctionsGL *functions,
|
||||
GLuint programID)
|
||||
: mPostLinkImplFunctor(functor), mFunctions(functions), mProgramID(programID)
|
||||
{}
|
||||
|
||||
angle::Result wait(const gl::Context *context) override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::LinkEventNativeParallel::wait");
|
||||
|
||||
GLint linkStatus = GL_FALSE;
|
||||
mFunctions->getProgramiv(mProgramID, GL_LINK_STATUS, &linkStatus);
|
||||
if (linkStatus == GL_TRUE)
|
||||
{
|
||||
return mPostLinkImplFunctor();
|
||||
}
|
||||
return angle::Result::Incomplete;
|
||||
}
|
||||
|
||||
bool isLinking() override
|
||||
{
|
||||
GLint completionStatus = GL_FALSE;
|
||||
mFunctions->getProgramiv(mProgramID, GL_COMPLETION_STATUS, &completionStatus);
|
||||
return completionStatus == GL_FALSE;
|
||||
}
|
||||
|
||||
private:
|
||||
PostLinkImplFunctor mPostLinkImplFunctor;
|
||||
const FunctionsGL *mFunctions;
|
||||
GLuint mProgramID;
|
||||
};
|
||||
|
||||
void ProgramGL::prepareForLink(const gl::ShaderMap<ShaderImpl *> &shaders)
|
||||
{
|
||||
for (gl::ShaderType shaderType : gl::AllShaderTypes())
|
||||
@@ -244,14 +276,20 @@ void ProgramGL::prepareForLink(const gl::ShaderMap<ShaderImpl *> &shaders)
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::ProgramMergedVaryings && /*mergedVaryings*/)
|
||||
angle::Result ProgramGL::link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::link");
|
||||
ProgramExecutableGL *executableGL = getExecutable();
|
||||
|
||||
executableGL->reset();
|
||||
*linkTaskOut = std::make_shared<LinkTaskGL>(this, mRenderer->hasNativeParallelCompile(),
|
||||
mFunctions, context->getExtensions(), mProgramID);
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
void ProgramGL::linkJobImpl(const gl::Extensions &extensions)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::linkJobImpl");
|
||||
ProgramExecutableGL *executableGL = getExecutable();
|
||||
|
||||
if (mAttachedShaders[gl::ShaderType::Compute] != 0)
|
||||
{
|
||||
@@ -261,14 +299,15 @@ std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context,
|
||||
{
|
||||
// Set the transform feedback state
|
||||
std::vector<std::string> transformFeedbackVaryingMappedNames;
|
||||
const gl::ShaderType tfShaderType =
|
||||
mState.getExecutable().hasLinkedShaderStage(gl::ShaderType::Geometry)
|
||||
? gl::ShaderType::Geometry
|
||||
: gl::ShaderType::Vertex;
|
||||
const gl::SharedCompiledShaderState &tfShaderState = mState.getAttachedShader(tfShaderType);
|
||||
for (const auto &tfVarying : mState.getTransformFeedbackVaryingNames())
|
||||
{
|
||||
gl::ShaderType tfShaderType =
|
||||
mState.getExecutable().hasLinkedShaderStage(gl::ShaderType::Geometry)
|
||||
? gl::ShaderType::Geometry
|
||||
: gl::ShaderType::Vertex;
|
||||
std::string tfVaryingMappedName = GetTransformFeedbackVaryingMappedName(
|
||||
mState.getAttachedShader(tfShaderType), tfVarying);
|
||||
std::string tfVaryingMappedName =
|
||||
GetTransformFeedbackVaryingMappedName(tfShaderState, tfVarying);
|
||||
transformFeedbackVaryingMappedNames.push_back(tfVaryingMappedName);
|
||||
}
|
||||
|
||||
@@ -321,7 +360,7 @@ std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context,
|
||||
// Bind the secondary fragment color outputs defined in EXT_blend_func_extended. We only use
|
||||
// the API to bind fragment output locations in case EXT_blend_func_extended is enabled.
|
||||
// Otherwise shader-assigned locations will work.
|
||||
if (context->getExtensions().blendFuncExtendedEXT)
|
||||
if (extensions.blendFuncExtendedEXT)
|
||||
{
|
||||
const gl::SharedCompiledShaderState &fragmentShader =
|
||||
mState.getAttachedShader(gl::ShaderType::Fragment);
|
||||
@@ -423,49 +462,44 @@ std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context,
|
||||
}
|
||||
}
|
||||
}
|
||||
auto workerPool = context->getShaderCompileThreadPool();
|
||||
|
||||
auto postLinkImplTask = [this, &resources]() {
|
||||
if (mAttachedShaders[gl::ShaderType::Compute] != 0)
|
||||
{
|
||||
mFunctions->detachShader(mProgramID, mAttachedShaders[gl::ShaderType::Compute]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
|
||||
{
|
||||
if (mAttachedShaders[shaderType] != 0)
|
||||
{
|
||||
mFunctions->detachShader(mProgramID, mAttachedShaders[shaderType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Verify the link
|
||||
if (!checkLinkStatus())
|
||||
{
|
||||
return angle::Result::Incomplete;
|
||||
}
|
||||
|
||||
if (mFeatures.alwaysCallUseProgramAfterLink.enabled)
|
||||
{
|
||||
mStateManager->forceUseProgram(mProgramID);
|
||||
}
|
||||
|
||||
linkResources(resources);
|
||||
getExecutable()->postLink(mFunctions, mFeatures, mProgramID);
|
||||
|
||||
return angle::Result::Continue;
|
||||
};
|
||||
|
||||
mFunctions->linkProgram(mProgramID);
|
||||
if (mRenderer->hasNativeParallelCompile())
|
||||
}
|
||||
|
||||
angle::Result ProgramGL::postLinkJobImpl(const gl::ProgramLinkedResources &resources)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramGL::postLinkJobImpl");
|
||||
|
||||
if (mAttachedShaders[gl::ShaderType::Compute] != 0)
|
||||
{
|
||||
return std::make_unique<LinkEventNativeParallel>(postLinkImplTask, mFunctions, mProgramID);
|
||||
mFunctions->detachShader(mProgramID, mAttachedShaders[gl::ShaderType::Compute]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(postLinkImplTask());
|
||||
for (const gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
|
||||
{
|
||||
if (mAttachedShaders[shaderType] != 0)
|
||||
{
|
||||
mFunctions->detachShader(mProgramID, mAttachedShaders[shaderType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the link
|
||||
if (!checkLinkStatus())
|
||||
{
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
|
||||
if (mFeatures.alwaysCallUseProgramAfterLink.enabled)
|
||||
{
|
||||
mStateManager->forceUseProgram(mProgramID);
|
||||
}
|
||||
|
||||
linkResources(resources);
|
||||
getExecutable()->postLink(mFunctions, mFeatures, mProgramID);
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
GLboolean ProgramGL::validate(const gl::Caps & /*caps*/)
|
||||
|
||||
@@ -39,16 +39,16 @@ class ProgramGL : public ProgramImpl
|
||||
|
||||
void destroy(const gl::Context *context) override;
|
||||
|
||||
std::unique_ptr<LinkEvent> load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream) override;
|
||||
angle::Result load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream,
|
||||
std::shared_ptr<LinkTask> *loadTaskOut) override;
|
||||
void save(const gl::Context *context, gl::BinaryOutputStream *stream) override;
|
||||
void setBinaryRetrievableHint(bool retrievable) override;
|
||||
void setSeparable(bool separable) override;
|
||||
|
||||
void prepareForLink(const gl::ShaderMap<ShaderImpl *> &shaders) override;
|
||||
std::unique_ptr<LinkEvent> link(const gl::Context *contextImpl,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::ProgramMergedVaryings &&mergedVaryings) override;
|
||||
angle::Result link(const gl::Context *contextImpl,
|
||||
std::shared_ptr<LinkTask> *linkTaskOut) override;
|
||||
GLboolean validate(const gl::Caps &caps) override;
|
||||
|
||||
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
|
||||
@@ -123,9 +123,14 @@ class ProgramGL : public ProgramImpl
|
||||
}
|
||||
|
||||
private:
|
||||
class LinkTask;
|
||||
class LinkEventNativeParallel;
|
||||
class LinkEventGL;
|
||||
class LinkTaskGL;
|
||||
class PostLinkGL;
|
||||
|
||||
friend class LinkTaskGL;
|
||||
friend class PostLinkGL;
|
||||
|
||||
void linkJobImpl(const gl::Extensions &extensions);
|
||||
angle::Result postLinkJobImpl(const gl::ProgramLinkedResources &resources);
|
||||
|
||||
bool checkLinkStatus();
|
||||
|
||||
|
||||
@@ -2608,6 +2608,15 @@ void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFea
|
||||
// https://crbug.com/480992
|
||||
// Disable shader program cache to workaround PowerVR Rogue issues.
|
||||
ANGLE_FEATURE_CONDITION(features, disableProgramBinary, IsPowerVrRogue(functions));
|
||||
|
||||
// The link job needs a context, and previous experiments showed setting up temp contexts in
|
||||
// threads for the sake of program link triggers too many driver bugs. See
|
||||
// https://chromium-review.googlesource.com/c/angle/angle/+/4774785 for context.
|
||||
//
|
||||
// As a result, the link job is done in the same thread as the link call. If the native driver
|
||||
// supports parallel link, it's still done internally by the driver, and ANGLE supports delaying
|
||||
// post-link operations until that is done.
|
||||
ANGLE_FEATURE_CONDITION(features, linkJobIsNotThreadSafe, true);
|
||||
}
|
||||
|
||||
void ReInitializeFeaturesAtGPUSwitch(const FunctionsGL *functions, angle::FeaturesGL *features)
|
||||
|
||||
@@ -109,6 +109,8 @@ class DisplayMtl : public DisplayImpl
|
||||
egl::Surface *readSurface,
|
||||
gl::Context *context) override;
|
||||
|
||||
void initializeFrontendFeatures(angle::FrontendFeatures *features) const override;
|
||||
|
||||
void populateFeatureList(angle::FeatureList *features) override;
|
||||
|
||||
bool isValidNativeWindow(EGLNativeWindowType window) const override;
|
||||
|
||||
@@ -516,6 +516,15 @@ void DisplayMtl::generateCaps(egl::Caps *outCaps) const
|
||||
outCaps->textureNPOT = true;
|
||||
}
|
||||
|
||||
void DisplayMtl::initializeFrontendFeatures(angle::FrontendFeatures *features) const
|
||||
{
|
||||
// The link job in this backend references gl::Context and ContextMtl, and thread-safety is not
|
||||
// guaranteed. The link subtasks are safe however, they are still parallelized.
|
||||
//
|
||||
// Once the link jobs are made thread-safe and using mtl::Context, this feature can be removed.
|
||||
ANGLE_FEATURE_CONDITION(features, linkJobIsNotThreadSafe, true);
|
||||
}
|
||||
|
||||
void DisplayMtl::populateFeatureList(angle::FeatureList *features)
|
||||
{
|
||||
mFeatures.populateFeatureList(features);
|
||||
|
||||
@@ -318,7 +318,15 @@ DefaultUniformBlockMtl::~DefaultUniformBlockMtl() = default;
|
||||
|
||||
ProgramExecutableMtl::ProgramExecutableMtl(const gl::ProgramExecutable *executable)
|
||||
: ProgramExecutableImpl(executable), mProgramHasFlatAttributes(false), mShadowCompareModes{}
|
||||
{}
|
||||
{
|
||||
mCurrentShaderVariants.fill(nullptr);
|
||||
|
||||
for (gl::ShaderType shaderType : gl::AllShaderTypes())
|
||||
{
|
||||
mMslShaderTranslateInfo[shaderType].reset();
|
||||
}
|
||||
mMslXfbOnlyVertexShaderInfo.reset();
|
||||
}
|
||||
|
||||
ProgramExecutableMtl::~ProgramExecutableMtl() {}
|
||||
|
||||
|
||||
@@ -35,16 +35,15 @@ class ProgramMtl : public ProgramImpl
|
||||
|
||||
void destroy(const gl::Context *context) override;
|
||||
|
||||
std::unique_ptr<LinkEvent> load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream) override;
|
||||
angle::Result load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream,
|
||||
std::shared_ptr<LinkTask> *loadTaskOut) override;
|
||||
void save(const gl::Context *context, gl::BinaryOutputStream *stream) override;
|
||||
void setBinaryRetrievableHint(bool retrievable) override;
|
||||
void setSeparable(bool separable) override;
|
||||
|
||||
void prepareForLink(const gl::ShaderMap<ShaderImpl *> &shaders) override;
|
||||
std::unique_ptr<LinkEvent> link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::ProgramMergedVaryings &&mergedVaryings) override;
|
||||
angle::Result link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut) override;
|
||||
GLboolean validate(const gl::Caps &caps) override;
|
||||
|
||||
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
|
||||
@@ -107,8 +106,14 @@ class ProgramMtl : public ProgramImpl
|
||||
ProgramExecutableMtl *getExecutable() { return mtl::GetImpl(&mState.getExecutable()); }
|
||||
|
||||
private:
|
||||
class ProgramLinkEvent;
|
||||
class CompileMslTask;
|
||||
class LinkTaskMtl;
|
||||
class LoadTaskMtl;
|
||||
|
||||
friend class LinkTaskMtl;
|
||||
|
||||
angle::Result linkJobImpl(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
std::vector<std::shared_ptr<LinkSubTask>> *subTasksOut);
|
||||
|
||||
template <int cols, int rows>
|
||||
void setUniformMatrixfv(GLint location,
|
||||
@@ -121,10 +126,9 @@ class ProgramMtl : public ProgramImpl
|
||||
template <typename T>
|
||||
void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType);
|
||||
|
||||
void reset(ContextMtl *context);
|
||||
|
||||
void linkResources(const gl::ProgramLinkedResources &resources);
|
||||
std::unique_ptr<LinkEvent> compileMslShaderLibs(const gl::Context *context);
|
||||
angle::Result compileMslShaderLibs(const gl::Context *context,
|
||||
std::vector<std::shared_ptr<LinkSubTask>> *subTasksOut);
|
||||
|
||||
gl::ShaderMap<SharedCompiledShaderStateMtl> mAttachedShaders;
|
||||
};
|
||||
|
||||
@@ -29,9 +29,6 @@
|
||||
#include "libANGLE/renderer/renderer_utils.h"
|
||||
#include "libANGLE/trace.h"
|
||||
|
||||
#define ANGLE_PARALLEL_LINK_RETURN(X) return std::make_unique<LinkEventDone>(X)
|
||||
#define ANGLE_PARALLEL_LINK_TRY(EXPR) ANGLE_TRY_TEMPLATE(EXPR, ANGLE_PARALLEL_LINK_RETURN)
|
||||
|
||||
namespace rx
|
||||
{
|
||||
|
||||
@@ -129,8 +126,94 @@ class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFacto
|
||||
public:
|
||||
sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std140BlockEncoder(); }
|
||||
};
|
||||
|
||||
class CompileMslTask final : public LinkSubTask
|
||||
{
|
||||
public:
|
||||
CompileMslTask(ContextMtl *context,
|
||||
mtl::TranslatedShaderInfo *translatedMslInfo,
|
||||
const std::map<std::string, std::string> &substitutionMacros)
|
||||
: mContext(context),
|
||||
mTranslatedMslInfo(translatedMslInfo),
|
||||
mSubstitutionMacros(substitutionMacros)
|
||||
{}
|
||||
~CompileMslTask() override = default;
|
||||
|
||||
void operator()() override
|
||||
{
|
||||
mResult = CreateMslShaderLib(mContext, mInfoLog, mTranslatedMslInfo, mSubstitutionMacros);
|
||||
}
|
||||
|
||||
angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
|
||||
{
|
||||
if (!mInfoLog.empty())
|
||||
{
|
||||
infoLog << mInfoLog.str();
|
||||
}
|
||||
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private:
|
||||
// TODO: remove this, inherit from mtl::Context and ensure thread-safety.
|
||||
// http://anglebug.com/8297
|
||||
ContextMtl *mContext;
|
||||
gl::InfoLog mInfoLog;
|
||||
mtl::TranslatedShaderInfo *mTranslatedMslInfo;
|
||||
std::map<std::string, std::string> mSubstitutionMacros;
|
||||
angle::Result mResult = angle::Result::Continue;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
class ProgramMtl::LinkTaskMtl final : public LinkTask
|
||||
{
|
||||
public:
|
||||
LinkTaskMtl(const gl::Context *context, ProgramMtl *program)
|
||||
: mContext(context), mProgram(program)
|
||||
{}
|
||||
~LinkTaskMtl() override = default;
|
||||
|
||||
std::vector<std::shared_ptr<LinkSubTask>> link(
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings) override
|
||||
{
|
||||
std::vector<std::shared_ptr<LinkSubTask>> subTasks;
|
||||
mResult = mProgram->linkJobImpl(mContext, resources, &subTasks);
|
||||
return subTasks;
|
||||
}
|
||||
|
||||
angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
|
||||
{
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private:
|
||||
// TODO: remove this, inherit from mtl::Context and ensure thread-safety.
|
||||
// http://anglebug.com/8297
|
||||
const gl::Context *mContext;
|
||||
ProgramMtl *mProgram;
|
||||
angle::Result mResult = angle::Result::Continue;
|
||||
};
|
||||
|
||||
class ProgramMtl::LoadTaskMtl final : public LinkTask
|
||||
{
|
||||
public:
|
||||
LoadTaskMtl(std::vector<std::shared_ptr<LinkSubTask>> &&subTasks)
|
||||
: mSubTasks(std::move(subTasks))
|
||||
{}
|
||||
~LoadTaskMtl() override = default;
|
||||
|
||||
std::vector<std::shared_ptr<LinkSubTask>> load() override { return mSubTasks; }
|
||||
|
||||
angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<LinkSubTask>> mSubTasks;
|
||||
};
|
||||
|
||||
// ProgramArgumentBufferEncoderMtl implementation
|
||||
void ProgramArgumentBufferEncoderMtl::reset(ContextMtl *contextMtl)
|
||||
{
|
||||
@@ -155,26 +238,26 @@ ProgramMtl::~ProgramMtl() = default;
|
||||
|
||||
void ProgramMtl::destroy(const gl::Context *context)
|
||||
{
|
||||
reset(mtl::GetImpl(context));
|
||||
getExecutable()->reset(mtl::GetImpl(context));
|
||||
}
|
||||
|
||||
void ProgramMtl::reset(ContextMtl *context)
|
||||
{
|
||||
getExecutable()->reset(context);
|
||||
}
|
||||
|
||||
std::unique_ptr<rx::LinkEvent> ProgramMtl::load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream)
|
||||
angle::Result ProgramMtl::load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream,
|
||||
std::shared_ptr<LinkTask> *loadTaskOut)
|
||||
{
|
||||
|
||||
ContextMtl *contextMtl = mtl::GetImpl(context);
|
||||
// NOTE(hqle): No transform feedbacks for now, since we only support ES 2.0 atm
|
||||
|
||||
reset(contextMtl);
|
||||
ANGLE_TRY(getExecutable()->load(contextMtl, stream));
|
||||
|
||||
ANGLE_PARALLEL_LINK_TRY(getExecutable()->load(contextMtl, stream));
|
||||
// TODO: parallelize the above too. http://anglebug.com/8297
|
||||
std::vector<std::shared_ptr<LinkSubTask>> subTasks;
|
||||
|
||||
return compileMslShaderLibs(context);
|
||||
ANGLE_TRY(compileMslShaderLibs(context, &subTasks));
|
||||
|
||||
*loadTaskOut = std::shared_ptr<LinkTask>(new LoadTaskMtl(std::move(subTasks)));
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
void ProgramMtl::save(const gl::Context *context, gl::BinaryOutputStream *stream)
|
||||
@@ -203,9 +286,15 @@ void ProgramMtl::prepareForLink(const gl::ShaderMap<ShaderImpl *> &shaders)
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::ProgramMergedVaryings &&mergedVaryings)
|
||||
angle::Result ProgramMtl::link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut)
|
||||
{
|
||||
*linkTaskOut = std::shared_ptr<LinkTask>(new LinkTaskMtl(context, this));
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result ProgramMtl::linkJobImpl(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
std::vector<std::shared_ptr<LinkSubTask>> *subTasksOut)
|
||||
{
|
||||
ContextMtl *contextMtl = mtl::GetImpl(context);
|
||||
ProgramExecutableMtl *executableMtl = getExecutable();
|
||||
@@ -214,95 +303,24 @@ std::unique_ptr<LinkEvent> ProgramMtl::link(const gl::Context *context,
|
||||
// assignment done in that function.
|
||||
linkResources(resources);
|
||||
|
||||
reset(contextMtl);
|
||||
ANGLE_PARALLEL_LINK_TRY(
|
||||
executableMtl->initDefaultUniformBlocks(contextMtl, mState.getAttachedShaders()));
|
||||
ANGLE_TRY(executableMtl->initDefaultUniformBlocks(contextMtl, mState.getAttachedShaders()));
|
||||
executableMtl->linkUpdateHasFlatAttributes(mState.getAttachedShader(gl::ShaderType::Vertex));
|
||||
|
||||
gl::ShaderMap<std::string> shaderSources;
|
||||
mtl::MSLGetShaderSource(mState, resources, &shaderSources);
|
||||
|
||||
ANGLE_PARALLEL_LINK_TRY(mtl::MTLGetMSL(contextMtl, mState.getExecutable(),
|
||||
contextMtl->getCaps(), shaderSources, mAttachedShaders,
|
||||
&executableMtl->mMslShaderTranslateInfo));
|
||||
ANGLE_TRY(mtl::MTLGetMSL(contextMtl, mState.getExecutable(), contextMtl->getCaps(),
|
||||
shaderSources, mAttachedShaders,
|
||||
&executableMtl->mMslShaderTranslateInfo));
|
||||
executableMtl->mMslXfbOnlyVertexShaderInfo =
|
||||
executableMtl->mMslShaderTranslateInfo[gl::ShaderType::Vertex];
|
||||
|
||||
return compileMslShaderLibs(context);
|
||||
return compileMslShaderLibs(context, subTasksOut);
|
||||
}
|
||||
|
||||
class ProgramMtl::CompileMslTask final : public angle::Closure
|
||||
{
|
||||
public:
|
||||
CompileMslTask(ContextMtl *context,
|
||||
mtl::TranslatedShaderInfo *translatedMslInfo,
|
||||
const std::map<std::string, std::string> &substitutionMacros)
|
||||
: mContext(context),
|
||||
mTranslatedMslInfo(translatedMslInfo),
|
||||
mSubstitutionMacros(substitutionMacros)
|
||||
{}
|
||||
|
||||
void operator()() override
|
||||
{
|
||||
mResult = CreateMslShaderLib(mContext, mInfoLog, mTranslatedMslInfo, mSubstitutionMacros);
|
||||
}
|
||||
|
||||
angle::Result getResult(gl::InfoLog &infoLog)
|
||||
{
|
||||
if (!mInfoLog.empty())
|
||||
{
|
||||
infoLog << mInfoLog.str();
|
||||
}
|
||||
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private:
|
||||
ContextMtl *mContext;
|
||||
gl::InfoLog mInfoLog;
|
||||
mtl::TranslatedShaderInfo *mTranslatedMslInfo;
|
||||
std::map<std::string, std::string> mSubstitutionMacros;
|
||||
angle::Result mResult = angle::Result::Continue;
|
||||
};
|
||||
|
||||
// The LinkEvent implementation for linking a Metal program
|
||||
class ProgramMtl::ProgramLinkEvent final : public LinkEvent
|
||||
{
|
||||
public:
|
||||
ProgramLinkEvent(gl::InfoLog &infoLog,
|
||||
std::shared_ptr<angle::WorkerThreadPool> workerPool,
|
||||
std::vector<std::shared_ptr<ProgramMtl::CompileMslTask>> &&compileTasks)
|
||||
: mInfoLog(infoLog), mTasks(std::move(compileTasks))
|
||||
{
|
||||
mWaitableEvents.reserve(mTasks.size());
|
||||
for (const auto &task : mTasks)
|
||||
{
|
||||
mWaitableEvents.push_back(workerPool->postWorkerTask(task));
|
||||
}
|
||||
}
|
||||
|
||||
bool isLinking() override { return !angle::WaitableEvent::AllReady(&mWaitableEvents); }
|
||||
|
||||
angle::Result wait(const gl::Context *context) override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramMtl::ProgramLinkEvent::wait");
|
||||
angle::WaitableEvent::WaitMany(&mWaitableEvents);
|
||||
|
||||
for (const auto &task : mTasks)
|
||||
{
|
||||
ANGLE_TRY(task->getResult(mInfoLog));
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
private:
|
||||
gl::InfoLog &mInfoLog;
|
||||
std::vector<std::shared_ptr<ProgramMtl::CompileMslTask>> mTasks;
|
||||
std::vector<std::shared_ptr<angle::WaitableEvent>> mWaitableEvents;
|
||||
};
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramMtl::compileMslShaderLibs(const gl::Context *context)
|
||||
angle::Result ProgramMtl::compileMslShaderLibs(
|
||||
const gl::Context *context,
|
||||
std::vector<std::shared_ptr<LinkSubTask>> *subTasksOut)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramMtl::compileMslShaderLibs");
|
||||
gl::InfoLog &infoLog = mState.getExecutable().getInfoLog();
|
||||
@@ -313,7 +331,6 @@ std::unique_ptr<LinkEvent> ProgramMtl::compileMslShaderLibs(const gl::Context *c
|
||||
contextMtl->getDisplay()->getFeatures().enableParallelMtlLibraryCompilation.enabled;
|
||||
mtl::LibraryCache &libraryCache = contextMtl->getDisplay()->getLibraryCache();
|
||||
|
||||
std::vector<std::shared_ptr<ProgramMtl::CompileMslTask>> asyncTasks;
|
||||
for (gl::ShaderType shaderType : gl::kAllGLES2ShaderTypes)
|
||||
{
|
||||
mtl::TranslatedShaderInfo *translateInfo =
|
||||
@@ -330,26 +347,16 @@ std::unique_ptr<LinkEvent> ProgramMtl::compileMslShaderLibs(const gl::Context *c
|
||||
{
|
||||
if (asyncCompile)
|
||||
{
|
||||
auto task =
|
||||
std::make_shared<ProgramMtl::CompileMslTask>(contextMtl, translateInfo, macros);
|
||||
asyncTasks.push_back(task);
|
||||
subTasksOut->emplace_back(new CompileMslTask(contextMtl, translateInfo, macros));
|
||||
}
|
||||
else
|
||||
{
|
||||
ANGLE_PARALLEL_LINK_TRY(
|
||||
CreateMslShaderLib(contextMtl, infoLog, translateInfo, macros));
|
||||
ANGLE_TRY(CreateMslShaderLib(contextMtl, infoLog, translateInfo, macros));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (asyncTasks.empty())
|
||||
{
|
||||
// All shaders were in the cache, no async work to do
|
||||
return std::make_unique<LinkEventDone>(angle::Result::Continue);
|
||||
}
|
||||
|
||||
return std::make_unique<ProgramMtl::ProgramLinkEvent>(
|
||||
infoLog, context->getShaderCompileThreadPool(), std::move(asyncTasks));
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
void ProgramMtl::linkResources(const gl::ProgramLinkedResources &resources)
|
||||
|
||||
@@ -13,15 +13,35 @@
|
||||
|
||||
namespace rx
|
||||
{
|
||||
namespace
|
||||
{
|
||||
class LinkTaskNULL : public LinkTask
|
||||
{
|
||||
public:
|
||||
~LinkTaskNULL() override = default;
|
||||
std::vector<std::shared_ptr<LinkSubTask>> link(
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
|
||||
{
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
ProgramNULL::ProgramNULL(const gl::ProgramState &state) : ProgramImpl(state) {}
|
||||
|
||||
ProgramNULL::~ProgramNULL() {}
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramNULL::load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream)
|
||||
angle::Result ProgramNULL::load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream,
|
||||
std::shared_ptr<LinkTask> *loadTaskOut)
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(angle::Result::Continue);
|
||||
*loadTaskOut = {};
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
void ProgramNULL::save(const gl::Context *context, gl::BinaryOutputStream *stream) {}
|
||||
@@ -30,11 +50,11 @@ void ProgramNULL::setBinaryRetrievableHint(bool retrievable) {}
|
||||
|
||||
void ProgramNULL::setSeparable(bool separable) {}
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramNULL::link(const gl::Context *contextImpl,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::ProgramMergedVaryings && /*mergedVaryings*/)
|
||||
angle::Result ProgramNULL::link(const gl::Context *contextImpl,
|
||||
std::shared_ptr<LinkTask> *linkTaskOut)
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(angle::Result::Continue);
|
||||
*linkTaskOut = std::shared_ptr<LinkTask>(new LinkTaskNULL);
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
GLboolean ProgramNULL::validate(const gl::Caps &caps)
|
||||
|
||||
@@ -21,15 +21,14 @@ class ProgramNULL : public ProgramImpl
|
||||
ProgramNULL(const gl::ProgramState &state);
|
||||
~ProgramNULL() override;
|
||||
|
||||
std::unique_ptr<LinkEvent> load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream) override;
|
||||
angle::Result load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream,
|
||||
std::shared_ptr<LinkTask> *loadTaskOut) override;
|
||||
void save(const gl::Context *context, gl::BinaryOutputStream *stream) override;
|
||||
void setBinaryRetrievableHint(bool retrievable) override;
|
||||
void setSeparable(bool separable) override;
|
||||
|
||||
std::unique_ptr<LinkEvent> link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::ProgramMergedVaryings &&mergedVaryings) override;
|
||||
angle::Result link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut) override;
|
||||
GLboolean validate(const gl::Caps &caps) override;
|
||||
|
||||
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
|
||||
|
||||
@@ -362,6 +362,7 @@ ProgramExecutableVk::ProgramExecutableVk(const gl::ProgramExecutable *executable
|
||||
mUniformBufferDescriptorType(VK_DESCRIPTOR_TYPE_MAX_ENUM),
|
||||
mDynamicUniformDescriptorOffsets{}
|
||||
{
|
||||
mDescriptorSets.fill(VK_NULL_HANDLE);
|
||||
for (std::shared_ptr<DefaultUniformBlockVk> &defaultBlock : mDefaultUniformBlocks)
|
||||
{
|
||||
defaultBlock = std::make_shared<DefaultUniformBlockVk>();
|
||||
@@ -499,9 +500,9 @@ angle::Result ProgramExecutableVk::ensurePipelineCacheInitialized(vk::Context *c
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(ContextVk *contextVk,
|
||||
bool isSeparable,
|
||||
gl::BinaryInputStream *stream)
|
||||
angle::Result ProgramExecutableVk::load(ContextVk *contextVk,
|
||||
bool isSeparable,
|
||||
gl::BinaryInputStream *stream)
|
||||
{
|
||||
mVariableInfoMap.load(stream);
|
||||
mOriginalShaderInfo.load(stream);
|
||||
@@ -528,33 +529,19 @@ std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(ContextVk *contextVk,
|
||||
stream->readBool(&compressedData);
|
||||
stream->readBytes(compressedPipelineData.data(), compressedPipelineDataSize);
|
||||
// Initialize the pipeline cache based on cached data.
|
||||
angle::Result status =
|
||||
initializePipelineCache(contextVk, compressedData, compressedPipelineData);
|
||||
if (status != angle::Result::Continue)
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(status);
|
||||
}
|
||||
ANGLE_TRY(initializePipelineCache(contextVk, compressedData, compressedPipelineData));
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize and resize the mDefaultUniformBlocks' memory
|
||||
angle::Result status = resizeUniformBlockMemory(contextVk, requiredBufferSize);
|
||||
if (status != angle::Result::Continue)
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(status);
|
||||
}
|
||||
ANGLE_TRY(resizeUniformBlockMemory(contextVk, requiredBufferSize));
|
||||
|
||||
resetLayout(contextVk);
|
||||
status = createPipelineLayout(contextVk, &contextVk->getPipelineLayoutCache(),
|
||||
&contextVk->getDescriptorSetLayoutCache(), nullptr);
|
||||
if (status != angle::Result::Continue)
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(status);
|
||||
}
|
||||
ANGLE_TRY(createPipelineLayout(contextVk, &contextVk->getPipelineLayoutCache(),
|
||||
&contextVk->getDescriptorSetLayoutCache(), nullptr));
|
||||
|
||||
status = initializeDescriptorPools(contextVk, &contextVk->getDescriptorSetLayoutCache(),
|
||||
&contextVk->getMetaDescriptorPools());
|
||||
return std::make_unique<LinkEventDone>(status);
|
||||
return initializeDescriptorPools(contextVk, &contextVk->getDescriptorSetLayoutCache(),
|
||||
&contextVk->getMetaDescriptorPools());
|
||||
}
|
||||
|
||||
void ProgramExecutableVk::save(ContextVk *contextVk,
|
||||
|
||||
@@ -121,9 +121,7 @@ class ProgramExecutableVk : public ProgramExecutableImpl
|
||||
void destroy(const gl::Context *context) override;
|
||||
|
||||
void save(ContextVk *contextVk, bool isSeparable, gl::BinaryOutputStream *stream);
|
||||
std::unique_ptr<rx::LinkEvent> load(ContextVk *contextVk,
|
||||
bool isSeparable,
|
||||
gl::BinaryInputStream *stream);
|
||||
angle::Result load(ContextVk *contextVk, bool isSeparable, gl::BinaryInputStream *stream);
|
||||
|
||||
void clearVariableInfoMap();
|
||||
|
||||
|
||||
@@ -48,34 +48,35 @@ class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFacto
|
||||
sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std140BlockEncoder(); }
|
||||
};
|
||||
|
||||
class LinkTaskVk final : public vk::Context, public angle::Closure
|
||||
class LinkTaskVk final : public vk::Context, public LinkTask
|
||||
{
|
||||
public:
|
||||
LinkTaskVk(RendererVk *renderer,
|
||||
PipelineLayoutCache &pipelineLayoutCache,
|
||||
DescriptorSetLayoutCache &descriptorSetLayoutCache,
|
||||
const gl::ProgramState &state,
|
||||
gl::ProgramMergedVaryings &&mergedVaryings,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
bool isGLES1,
|
||||
vk::PipelineRobustness pipelineRobustness,
|
||||
vk::PipelineProtectedAccess pipelineProtectedAccess)
|
||||
: vk::Context(renderer),
|
||||
mState(state),
|
||||
mExecutable(&mState.getExecutable()),
|
||||
mMergedVaryings(std::move(mergedVaryings)),
|
||||
mResources(resources),
|
||||
mIsGLES1(isGLES1),
|
||||
mPipelineRobustness(pipelineRobustness),
|
||||
mPipelineProtectedAccess(pipelineProtectedAccess),
|
||||
mPipelineLayoutCache(pipelineLayoutCache),
|
||||
mDescriptorSetLayoutCache(descriptorSetLayoutCache)
|
||||
{}
|
||||
~LinkTaskVk() override = default;
|
||||
|
||||
void operator()() override
|
||||
std::vector<std::shared_ptr<LinkSubTask>> link(
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings) override
|
||||
{
|
||||
angle::Result result = linkImpl();
|
||||
angle::Result result = linkImpl(resources, mergedVaryings);
|
||||
ASSERT((result == angle::Result::Continue) == (mErrorCode == VK_SUCCESS));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void handleError(VkResult result,
|
||||
@@ -89,11 +90,12 @@ class LinkTaskVk final : public vk::Context, public angle::Closure
|
||||
mErrorLine = line;
|
||||
}
|
||||
|
||||
angle::Result getResult(ContextVk *contextVk)
|
||||
angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
|
||||
{
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
ProgramExecutableVk *executableVk = vk::GetImpl(mExecutable);
|
||||
|
||||
// Clean up garbage first, it's not no matter what may fail below.
|
||||
// Clean up garbage first, it's done no matter what may fail below.
|
||||
mCompatibleRenderPass.destroy(contextVk->getDevice());
|
||||
|
||||
ANGLE_TRY(executableVk->initializeDescriptorPools(contextVk,
|
||||
@@ -136,9 +138,10 @@ class LinkTaskVk final : public vk::Context, public angle::Closure
|
||||
}
|
||||
|
||||
private:
|
||||
angle::Result linkImpl();
|
||||
angle::Result linkImpl(const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings);
|
||||
|
||||
void linkResources();
|
||||
void linkResources(const gl::ProgramLinkedResources &resources);
|
||||
angle::Result initDefaultUniformBlocks();
|
||||
void generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> *layoutMapOut,
|
||||
gl::ShaderMap<size_t> *requiredBufferSizeOut);
|
||||
@@ -148,8 +151,6 @@ class LinkTaskVk final : public vk::Context, public angle::Closure
|
||||
// direclty access the state from a potentially parallel job.
|
||||
const gl::ProgramState &mState;
|
||||
const gl::ProgramExecutable *mExecutable;
|
||||
const gl::ProgramMergedVaryings mMergedVaryings;
|
||||
const gl::ProgramLinkedResources &mResources;
|
||||
const bool mIsGLES1;
|
||||
const vk::PipelineRobustness mPipelineRobustness;
|
||||
const vk::PipelineProtectedAccess mPipelineProtectedAccess;
|
||||
@@ -168,19 +169,20 @@ class LinkTaskVk final : public vk::Context, public angle::Closure
|
||||
unsigned int mErrorLine = 0;
|
||||
};
|
||||
|
||||
angle::Result LinkTaskVk::linkImpl()
|
||||
angle::Result LinkTaskVk::linkImpl(const gl::ProgramLinkedResources &resources,
|
||||
const gl::ProgramMergedVaryings &mergedVaryings)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVk::LinkTaskVk::run");
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "LinkTaskVk::linkImpl");
|
||||
ProgramExecutableVk *executableVk = vk::GetImpl(mExecutable);
|
||||
|
||||
// Link resources before calling GetShaderSource to make sure they are ready for the set/binding
|
||||
// assignment done in that function.
|
||||
linkResources();
|
||||
linkResources(resources);
|
||||
|
||||
executableVk->clearVariableInfoMap();
|
||||
|
||||
// Gather variable info and compiled SPIR-V binaries.
|
||||
executableVk->assignAllSpvLocations(this, mState, mResources);
|
||||
executableVk->assignAllSpvLocations(this, mState, resources);
|
||||
|
||||
gl::ShaderMap<const angle::spirv::Blob *> spirvBlobs;
|
||||
SpvGetShaderSpirvCode(mState, &spirvBlobs);
|
||||
@@ -188,7 +190,7 @@ angle::Result LinkTaskVk::linkImpl()
|
||||
if (getFeatures().varyingsRequireMatchingPrecisionInSpirv.enabled &&
|
||||
getFeatures().enablePrecisionQualifiers.enabled)
|
||||
{
|
||||
executableVk->resolvePrecisionMismatch(mMergedVaryings);
|
||||
executableVk->resolvePrecisionMismatch(mergedVaryings);
|
||||
}
|
||||
|
||||
// Compile the shaders.
|
||||
@@ -219,12 +221,12 @@ angle::Result LinkTaskVk::linkImpl()
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
void LinkTaskVk::linkResources()
|
||||
void LinkTaskVk::linkResources(const gl::ProgramLinkedResources &resources)
|
||||
{
|
||||
Std140BlockLayoutEncoderFactory std140EncoderFactory;
|
||||
gl::ProgramLinkedResourcesLinker linker(&std140EncoderFactory);
|
||||
|
||||
linker.linkResources(mState, mResources);
|
||||
linker.linkResources(mState, resources);
|
||||
}
|
||||
|
||||
angle::Result LinkTaskVk::initDefaultUniformBlocks()
|
||||
@@ -334,33 +336,6 @@ void LinkTaskVk::initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMa
|
||||
}
|
||||
}
|
||||
|
||||
// The event for parallelized/lockless link.
|
||||
class LinkEventVulkan final : public LinkEvent
|
||||
{
|
||||
public:
|
||||
LinkEventVulkan(std::shared_ptr<angle::WorkerThreadPool> workerPool,
|
||||
std::shared_ptr<LinkTaskVk> linkTask)
|
||||
: mLinkTask(linkTask),
|
||||
mWaitableEvent(
|
||||
std::shared_ptr<angle::WaitableEvent>(workerPool->postWorkerTask(mLinkTask)))
|
||||
{}
|
||||
|
||||
angle::Result wait(const gl::Context *context) override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVK::LinkEvent::wait");
|
||||
|
||||
mWaitableEvent->wait();
|
||||
|
||||
return mLinkTask->getResult(vk::GetImpl(context));
|
||||
}
|
||||
|
||||
bool isLinking() override { return !mWaitableEvent->isReady(); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<LinkTaskVk> mLinkTask;
|
||||
std::shared_ptr<angle::WaitableEvent> mWaitableEvent;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void UpdateDefaultUniformBlock(GLsizei count,
|
||||
uint32_t arrayIndex,
|
||||
@@ -430,20 +405,17 @@ ProgramVk::~ProgramVk() = default;
|
||||
void ProgramVk::destroy(const gl::Context *context)
|
||||
{
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
reset(contextVk);
|
||||
}
|
||||
|
||||
void ProgramVk::reset(ContextVk *contextVk)
|
||||
{
|
||||
getExecutable()->reset(contextVk);
|
||||
}
|
||||
|
||||
std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream)
|
||||
angle::Result ProgramVk::load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream,
|
||||
std::shared_ptr<LinkTask> *loadTaskOut)
|
||||
{
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
|
||||
reset(contextVk);
|
||||
// TODO: parallelize program load. http://anglebug.com/8297
|
||||
*loadTaskOut = {};
|
||||
|
||||
return getExecutable()->load(contextVk, mState.isSeparable(), stream);
|
||||
}
|
||||
@@ -464,21 +436,16 @@ void ProgramVk::setSeparable(bool separable)
|
||||
// Nothing to do here yet.
|
||||
}
|
||||
|
||||
std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::ProgramMergedVaryings &&mergedVaryings)
|
||||
angle::Result ProgramVk::link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVk::link");
|
||||
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
reset(contextVk);
|
||||
|
||||
std::shared_ptr<LinkTaskVk> linkTask = std::make_shared<LinkTaskVk>(
|
||||
*linkTaskOut = std::shared_ptr<LinkTask>(new LinkTaskVk(
|
||||
contextVk->getRenderer(), contextVk->getPipelineLayoutCache(),
|
||||
contextVk->getDescriptorSetLayoutCache(), mState, std::move(mergedVaryings), resources,
|
||||
context->getState().isGLES1(), contextVk->pipelineRobustness(),
|
||||
contextVk->pipelineProtectedAccess());
|
||||
return std::make_unique<LinkEventVulkan>(context->getShaderCompileThreadPool(), linkTask);
|
||||
contextVk->getDescriptorSetLayoutCache(), mState, context->getState().isGLES1(),
|
||||
contextVk->pipelineRobustness(), contextVk->pipelineProtectedAccess()));
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
GLboolean ProgramVk::validate(const gl::Caps &caps)
|
||||
|
||||
@@ -29,15 +29,14 @@ class ProgramVk : public ProgramImpl
|
||||
~ProgramVk() override;
|
||||
void destroy(const gl::Context *context) override;
|
||||
|
||||
std::unique_ptr<LinkEvent> load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream) override;
|
||||
angle::Result load(const gl::Context *context,
|
||||
gl::BinaryInputStream *stream,
|
||||
std::shared_ptr<LinkTask> *loadTaskOut) override;
|
||||
void save(const gl::Context *context, gl::BinaryOutputStream *stream) override;
|
||||
void setBinaryRetrievableHint(bool retrievable) override;
|
||||
void setSeparable(bool separable) override;
|
||||
|
||||
std::unique_ptr<LinkEvent> link(const gl::Context *context,
|
||||
const gl::ProgramLinkedResources &resources,
|
||||
gl::ProgramMergedVaryings &&mergedVaryings) override;
|
||||
angle::Result link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut) override;
|
||||
GLboolean validate(const gl::Caps &caps) override;
|
||||
|
||||
angle::Result syncState(const gl::Context *context,
|
||||
@@ -109,8 +108,6 @@ class ProgramVk : public ProgramImpl
|
||||
GLboolean transpose,
|
||||
const GLfloat *value);
|
||||
|
||||
void reset(ContextVk *contextVk);
|
||||
|
||||
template <class T>
|
||||
void getUniformImpl(GLint location, T *v, GLenum entryPointType) const;
|
||||
|
||||
|
||||
@@ -195,6 +195,7 @@ constexpr PackedEnumMap<Feature, const char *> kFeatureNames = {{
|
||||
{Feature::LimitMaxMSAASamplesTo4, "limitMaxMSAASamplesTo4"},
|
||||
{Feature::LimitSampleCountTo2, "limitSampleCountTo2"},
|
||||
{Feature::LimitWebglMaxTextureSizeTo4096, "limitWebglMaxTextureSizeTo4096"},
|
||||
{Feature::LinkJobIsNotThreadSafe, "linkJobIsNotThreadSafe"},
|
||||
{Feature::LoadMetalShadersFromBlobCache, "loadMetalShadersFromBlobCache"},
|
||||
{Feature::LogMemoryReportCallbacks, "logMemoryReportCallbacks"},
|
||||
{Feature::LogMemoryReportStats, "logMemoryReportStats"},
|
||||
|
||||
@@ -195,6 +195,7 @@ enum class Feature
|
||||
LimitMaxMSAASamplesTo4,
|
||||
LimitSampleCountTo2,
|
||||
LimitWebglMaxTextureSizeTo4096,
|
||||
LinkJobIsNotThreadSafe,
|
||||
LoadMetalShadersFromBlobCache,
|
||||
LogMemoryReportCallbacks,
|
||||
LogMemoryReportStats,
|
||||
|
||||
Reference in New Issue
Block a user