mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-03 14:09:33 +03:00
Reland: Vulkan: Move default uniform init to link job
This is a reland of d8cd4dcdc9
Bug: angleproject:8297
Change-Id: Ib4f8e9dd258da71d44983bbb619b6b4abda0b109
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4793218
Reviewed-by: Charlie Lao <cclao@google.com>
Reviewed-by: Yuxin Hu <yuxinhu@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
committed by
Angle LUCI CQ
parent
865eceaa2a
commit
8f64b51d22
@@ -1125,7 +1125,7 @@ GLuint Context::createShaderProgramv(ShaderType type, GLsizei count, const GLcha
|
||||
// We must wait to mark the program separable until it's successfully compiled.
|
||||
programObject->setSeparable(true);
|
||||
|
||||
programObject->attachShader(shaderObject);
|
||||
programObject->attachShader(this, shaderObject);
|
||||
|
||||
if (programObject->link(this) != angle::Result::Continue)
|
||||
{
|
||||
@@ -6155,7 +6155,7 @@ void Context::attachShader(ShaderProgramID program, ShaderProgramID shader)
|
||||
Program *programObject = mState.mShaderProgramManager->getProgram(program);
|
||||
Shader *shaderObject = mState.mShaderProgramManager->getShader(shader);
|
||||
ASSERT(programObject && shaderObject);
|
||||
programObject->attachShader(shaderObject);
|
||||
programObject->attachShader(this, shaderObject);
|
||||
}
|
||||
|
||||
void Context::copyBufferSubData(BufferBinding readTarget,
|
||||
|
||||
@@ -672,8 +672,8 @@ angle::Result GLES1Renderer::linkProgram(Context *context,
|
||||
|
||||
*programOut = program;
|
||||
|
||||
programObject->attachShader(getShader(vertexShader));
|
||||
programObject->attachShader(getShader(fragmentShader));
|
||||
programObject->attachShader(context, getShader(vertexShader));
|
||||
programObject->attachShader(context, getShader(fragmentShader));
|
||||
|
||||
for (auto it : attribLocs)
|
||||
{
|
||||
|
||||
@@ -1144,8 +1144,9 @@ const std::string &Program::getLabel() const
|
||||
return mState.mLabel;
|
||||
}
|
||||
|
||||
void Program::attachShader(Shader *shader)
|
||||
void Program::attachShader(const Context *context, Shader *shader)
|
||||
{
|
||||
resolveLink(context);
|
||||
ShaderType shaderType = shader->getType();
|
||||
ASSERT(shaderType != ShaderType::InvalidEnum);
|
||||
|
||||
|
||||
@@ -456,7 +456,7 @@ class Program final : public LabeledObject, public angle::Subject
|
||||
return mProgram;
|
||||
}
|
||||
|
||||
void attachShader(Shader *shader);
|
||||
void attachShader(const Context *context, Shader *shader);
|
||||
void detachShader(const Context *context, Shader *shader);
|
||||
int getAttachedShadersCount() const;
|
||||
|
||||
|
||||
@@ -1867,7 +1867,7 @@ void ProgramExecutableVk::onProgramBind(const gl::ProgramExecutable &glExecutabl
|
||||
}
|
||||
|
||||
angle::Result ProgramExecutableVk::resizeUniformBlockMemory(
|
||||
ContextVk *contextVk,
|
||||
vk::Context *context,
|
||||
const gl::ProgramExecutable &glExecutable,
|
||||
const gl::ShaderMap<size_t> &requiredBufferSize)
|
||||
{
|
||||
@@ -1878,7 +1878,7 @@ angle::Result ProgramExecutableVk::resizeUniformBlockMemory(
|
||||
if (!mDefaultUniformBlocks[shaderType]->uniformData.resize(
|
||||
requiredBufferSize[shaderType]))
|
||||
{
|
||||
ANGLE_VK_CHECK(contextVk, false, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
ANGLE_VK_CHECK(context, false, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
}
|
||||
|
||||
// Initialize uniform buffer memory to zero by default.
|
||||
|
||||
@@ -277,6 +277,11 @@ class ProgramExecutableVk
|
||||
const gl::Program::DirtyBits &getDirtyBits() const { return mDirtyBits; }
|
||||
void resetUniformBufferDirtyBits() { mDirtyBits.reset(); }
|
||||
|
||||
// The following functions are for internal use of programs, including from a threaded link job:
|
||||
angle::Result resizeUniformBlockMemory(vk::Context *context,
|
||||
const gl::ProgramExecutable &glExecutable,
|
||||
const gl::ShaderMap<size_t> &requiredBufferSize);
|
||||
|
||||
private:
|
||||
friend class ProgramVk;
|
||||
friend class ProgramPipelineVk;
|
||||
@@ -368,10 +373,6 @@ class ProgramExecutableVk
|
||||
const vk::GraphicsPipelineDesc **descPtrOut,
|
||||
vk::PipelineHelper **pipelineOut);
|
||||
|
||||
angle::Result resizeUniformBlockMemory(ContextVk *contextVk,
|
||||
const gl::ProgramExecutable &glExecutable,
|
||||
const gl::ShaderMap<size_t> &requiredBufferSize);
|
||||
|
||||
angle::Result getOrAllocateDescriptorSet(vk::Context *context,
|
||||
UpdateDescriptorSetsBuilder *updateBuilder,
|
||||
vk::CommandBufferHelperCommon *commandBufferHelper,
|
||||
|
||||
@@ -22,16 +22,36 @@ namespace rx
|
||||
|
||||
namespace
|
||||
{
|
||||
class LinkTask final : public vk::Context, public angle::Closure
|
||||
// Identical to Std140 encoder in all aspects, except it ignores opaque uniform types.
|
||||
class VulkanDefaultBlockEncoder : public sh::Std140BlockEncoder
|
||||
{
|
||||
public:
|
||||
LinkTask(RendererVk *renderer,
|
||||
const gl::ProgramState &state,
|
||||
const gl::ProgramExecutable &glExecutable,
|
||||
ProgramExecutableVk *executable,
|
||||
bool isGLES1,
|
||||
vk::PipelineRobustness pipelineRobustness,
|
||||
vk::PipelineProtectedAccess pipelineProtectedAccess)
|
||||
void advanceOffset(GLenum type,
|
||||
const std::vector<unsigned int> &arraySizes,
|
||||
bool isRowMajorMatrix,
|
||||
int arrayStride,
|
||||
int matrixStride) override
|
||||
{
|
||||
if (gl::IsOpaqueType(type))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sh::Std140BlockEncoder::advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride,
|
||||
matrixStride);
|
||||
}
|
||||
};
|
||||
|
||||
class LinkTaskVk final : public vk::Context, public angle::Closure
|
||||
{
|
||||
public:
|
||||
LinkTaskVk(RendererVk *renderer,
|
||||
const gl::ProgramState &state,
|
||||
const gl::ProgramExecutable &glExecutable,
|
||||
ProgramExecutableVk *executable,
|
||||
bool isGLES1,
|
||||
vk::PipelineRobustness pipelineRobustness,
|
||||
vk::PipelineProtectedAccess pipelineProtectedAccess)
|
||||
: vk::Context(renderer),
|
||||
mState(state),
|
||||
mGlExecutable(glExecutable),
|
||||
@@ -41,7 +61,11 @@ class LinkTask final : public vk::Context, public angle::Closure
|
||||
mPipelineProtectedAccess(pipelineProtectedAccess)
|
||||
{}
|
||||
|
||||
void operator()() override;
|
||||
void operator()() override
|
||||
{
|
||||
angle::Result result = linkImpl();
|
||||
ASSERT((result == angle::Result::Continue) == (mErrorCode == VK_SUCCESS));
|
||||
}
|
||||
|
||||
void handleError(VkResult result,
|
||||
const char *file,
|
||||
@@ -78,6 +102,13 @@ class LinkTask final : public vk::Context, public angle::Closure
|
||||
}
|
||||
|
||||
private:
|
||||
angle::Result linkImpl();
|
||||
|
||||
angle::Result initDefaultUniformBlocks();
|
||||
void generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> *layoutMapOut,
|
||||
gl::ShaderMap<size_t> *requiredBufferSizeOut);
|
||||
void initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> *layoutMapOut);
|
||||
|
||||
// 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.
|
||||
const gl::ProgramState &mState;
|
||||
@@ -97,9 +128,11 @@ class LinkTask final : public vk::Context, public angle::Closure
|
||||
unsigned int mErrorLine = 0;
|
||||
};
|
||||
|
||||
void LinkTask::operator()()
|
||||
angle::Result LinkTaskVk::linkImpl()
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVk::LinkTask::run");
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVk::LinkTaskVk::run");
|
||||
|
||||
ANGLE_TRY(initDefaultUniformBlocks());
|
||||
|
||||
// Warm up the pipeline cache by creating a few placeholder pipelines. This is not done for
|
||||
// separable programs, and is deferred to when the program pipeline is finalized.
|
||||
@@ -113,60 +146,27 @@ void LinkTask::operator()()
|
||||
// - Individual GLES1 tests are long, and this adds a considerable overhead to those tests
|
||||
if (!mState.isSeparable() && !mIsGLES1)
|
||||
{
|
||||
angle::Result result =
|
||||
mExecutable->warmUpPipelineCache(this, mGlExecutable, mPipelineRobustness,
|
||||
mPipelineProtectedAccess, &mCompatibleRenderPass);
|
||||
|
||||
ASSERT((result == angle::Result::Continue) == (mErrorCode == VK_SUCCESS));
|
||||
ANGLE_TRY(mExecutable->warmUpPipelineCache(this, mGlExecutable, mPipelineRobustness,
|
||||
mPipelineProtectedAccess,
|
||||
&mCompatibleRenderPass));
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
// The event for parallelized/lockless link.
|
||||
class LinkEventVulkan final : public LinkEvent
|
||||
angle::Result LinkTaskVk::initDefaultUniformBlocks()
|
||||
{
|
||||
public:
|
||||
LinkEventVulkan(std::shared_ptr<angle::WorkerThreadPool> workerPool,
|
||||
std::shared_ptr<LinkTask> linkTask)
|
||||
: mLinkTask(linkTask),
|
||||
mWaitableEvent(
|
||||
std::shared_ptr<angle::WaitableEvent>(workerPool->postWorkerTask(mLinkTask)))
|
||||
{}
|
||||
// Process vertex and fragment uniforms into std140 packing.
|
||||
gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
|
||||
gl::ShaderMap<size_t> requiredBufferSize;
|
||||
requiredBufferSize.fill(0);
|
||||
|
||||
angle::Result wait(const gl::Context *context) override
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVK::LinkEvent::wait");
|
||||
generateUniformLayoutMapping(&layoutMap, &requiredBufferSize);
|
||||
initDefaultUniformLayoutMapping(&layoutMap);
|
||||
|
||||
mWaitableEvent->wait();
|
||||
|
||||
return mLinkTask->getResult(vk::GetImpl(context));
|
||||
}
|
||||
|
||||
bool isLinking() override { return !mWaitableEvent->isReady(); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<LinkTask> mLinkTask;
|
||||
std::shared_ptr<angle::WaitableEvent> mWaitableEvent;
|
||||
};
|
||||
|
||||
// Identical to Std140 encoder in all aspects, except it ignores opaque uniform types.
|
||||
class VulkanDefaultBlockEncoder : public sh::Std140BlockEncoder
|
||||
{
|
||||
public:
|
||||
void advanceOffset(GLenum type,
|
||||
const std::vector<unsigned int> &arraySizes,
|
||||
bool isRowMajorMatrix,
|
||||
int arrayStride,
|
||||
int matrixStride) override
|
||||
{
|
||||
if (gl::IsOpaqueType(type))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sh::Std140BlockEncoder::advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride,
|
||||
matrixStride);
|
||||
}
|
||||
};
|
||||
// All uniform initializations are complete, now resize the buffers accordingly and return
|
||||
return mExecutable->resizeUniformBlockMemory(this, mGlExecutable, requiredBufferSize);
|
||||
}
|
||||
|
||||
void InitDefaultUniformBlock(const std::vector<sh::ShaderVariable> &uniforms,
|
||||
sh::BlockLayoutMap *blockLayoutMapOut,
|
||||
@@ -194,6 +194,97 @@ void InitDefaultUniformBlock(const std::vector<sh::ShaderVariable> &uniforms,
|
||||
return;
|
||||
}
|
||||
|
||||
void LinkTaskVk::generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> *layoutMapOut,
|
||||
gl::ShaderMap<size_t> *requiredBufferSizeOut)
|
||||
{
|
||||
for (const gl::ShaderType shaderType : mGlExecutable.getLinkedShaderStages())
|
||||
{
|
||||
const gl::SharedCompiledShaderState &shader = mState.getAttachedShader(shaderType);
|
||||
|
||||
if (shader)
|
||||
{
|
||||
const std::vector<sh::ShaderVariable> &uniforms = shader->uniforms;
|
||||
InitDefaultUniformBlock(uniforms, &(*layoutMapOut)[shaderType],
|
||||
&(*requiredBufferSizeOut)[shaderType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinkTaskVk::initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> *layoutMapOut)
|
||||
{
|
||||
// Init the default block layout info.
|
||||
const auto &uniforms = mGlExecutable.getUniforms();
|
||||
|
||||
for (const gl::VariableLocation &location : mState.getUniformLocations())
|
||||
{
|
||||
gl::ShaderMap<sh::BlockMemberInfo> layoutInfo;
|
||||
|
||||
if (location.used() && !location.ignored)
|
||||
{
|
||||
const auto &uniform = uniforms[location.index];
|
||||
if (uniform.isInDefaultBlock() && !uniform.isSampler() && !uniform.isImage() &&
|
||||
!uniform.isFragmentInOut())
|
||||
{
|
||||
std::string uniformName = mGlExecutable.getUniformNameByIndex(location.index);
|
||||
if (uniform.isArray())
|
||||
{
|
||||
// Gets the uniform name without the [0] at the end.
|
||||
uniformName = gl::StripLastArrayIndex(uniformName);
|
||||
ASSERT(uniformName.size() !=
|
||||
mGlExecutable.getUniformNameByIndex(location.index).size());
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (const gl::ShaderType shaderType : mGlExecutable.getLinkedShaderStages())
|
||||
{
|
||||
auto it = (*layoutMapOut)[shaderType].find(uniformName);
|
||||
if (it != (*layoutMapOut)[shaderType].end())
|
||||
{
|
||||
found = true;
|
||||
layoutInfo[shaderType] = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(found);
|
||||
}
|
||||
}
|
||||
|
||||
for (const gl::ShaderType shaderType : mGlExecutable.getLinkedShaderStages())
|
||||
{
|
||||
mExecutable->getSharedDefaultUniformBlock(shaderType)
|
||||
->uniformLayout.push_back(layoutInfo[shaderType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
@@ -343,21 +434,13 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
|
||||
return std::make_unique<LinkEventDone>(status);
|
||||
}
|
||||
|
||||
status = initDefaultUniformBlocks(context);
|
||||
if (status != angle::Result::Continue)
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(status);
|
||||
}
|
||||
|
||||
// TODO(jie.a.chen@intel.com): Parallelize linking.
|
||||
// http://crbug.com/849576
|
||||
status = mExecutable.createPipelineLayout(contextVk, programExecutable, nullptr);
|
||||
if (status != angle::Result::Continue)
|
||||
{
|
||||
return std::make_unique<LinkEventDone>(status);
|
||||
}
|
||||
|
||||
std::shared_ptr<LinkTask> linkTask = std::make_shared<LinkTask>(
|
||||
std::shared_ptr<LinkTaskVk> linkTask = std::make_shared<LinkTaskVk>(
|
||||
contextVk->getRenderer(), mState, programExecutable, &mExecutable,
|
||||
context->getState().isGLES1(), contextVk->pipelineRobustness(),
|
||||
contextVk->pipelineProtectedAccess());
|
||||
@@ -372,90 +455,6 @@ void ProgramVk::linkResources(const gl::ProgramLinkedResources &resources)
|
||||
linker.linkResources(mState, resources);
|
||||
}
|
||||
|
||||
angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
|
||||
{
|
||||
ContextVk *contextVk = vk::GetImpl(glContext);
|
||||
|
||||
// Process vertex and fragment uniforms into std140 packing.
|
||||
gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
|
||||
gl::ShaderMap<size_t> requiredBufferSize;
|
||||
requiredBufferSize.fill(0);
|
||||
|
||||
generateUniformLayoutMapping(layoutMap, requiredBufferSize);
|
||||
initDefaultUniformLayoutMapping(layoutMap);
|
||||
|
||||
// All uniform initializations are complete, now resize the buffers accordingly and return
|
||||
return mExecutable.resizeUniformBlockMemory(contextVk, mState.getExecutable(),
|
||||
requiredBufferSize);
|
||||
}
|
||||
|
||||
void ProgramVk::generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap,
|
||||
gl::ShaderMap<size_t> &requiredBufferSize)
|
||||
{
|
||||
const gl::ProgramExecutable &glExecutable = mState.getExecutable();
|
||||
|
||||
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
|
||||
{
|
||||
const gl::SharedCompiledShaderState &shader = mState.getAttachedShader(shaderType);
|
||||
|
||||
if (shader)
|
||||
{
|
||||
const std::vector<sh::ShaderVariable> &uniforms = shader->uniforms;
|
||||
InitDefaultUniformBlock(uniforms, &layoutMap[shaderType],
|
||||
&requiredBufferSize[shaderType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProgramVk::initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap)
|
||||
{
|
||||
// Init the default block layout info.
|
||||
const auto &uniforms = mState.getUniforms();
|
||||
const gl::ProgramExecutable &glExecutable = mState.getExecutable();
|
||||
|
||||
for (const gl::VariableLocation &location : mState.getUniformLocations())
|
||||
{
|
||||
gl::ShaderMap<sh::BlockMemberInfo> layoutInfo;
|
||||
|
||||
if (location.used() && !location.ignored)
|
||||
{
|
||||
const auto &uniform = uniforms[location.index];
|
||||
if (uniform.isInDefaultBlock() && !uniform.isSampler() && !uniform.isImage() &&
|
||||
!uniform.isFragmentInOut())
|
||||
{
|
||||
std::string uniformName = glExecutable.getUniformNameByIndex(location.index);
|
||||
if (uniform.isArray())
|
||||
{
|
||||
// Gets the uniform name without the [0] at the end.
|
||||
uniformName = gl::StripLastArrayIndex(uniformName);
|
||||
ASSERT(uniformName.size() !=
|
||||
glExecutable.getUniformNameByIndex(location.index).size());
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
|
||||
{
|
||||
auto it = layoutMap[shaderType].find(uniformName);
|
||||
if (it != layoutMap[shaderType].end())
|
||||
{
|
||||
found = true;
|
||||
layoutInfo[shaderType] = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(found);
|
||||
}
|
||||
}
|
||||
|
||||
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
|
||||
{
|
||||
mExecutable.mDefaultUniformBlocks[shaderType]->uniformLayout.push_back(
|
||||
layoutInfo[shaderType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLboolean ProgramVk::validate(const gl::Caps &caps, gl::InfoLog *infoLog)
|
||||
{
|
||||
// No-op. The spec is very vague about the behavior of validation.
|
||||
|
||||
@@ -127,10 +127,6 @@ class ProgramVk : public ProgramImpl
|
||||
const GLfloat *value);
|
||||
|
||||
void reset(ContextVk *contextVk);
|
||||
angle::Result initDefaultUniformBlocks(const gl::Context *glContext);
|
||||
void generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap,
|
||||
gl::ShaderMap<size_t> &requiredBufferSize);
|
||||
void initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap);
|
||||
|
||||
template <class T>
|
||||
void getUniformImpl(GLint location, T *v, GLenum entryPointType) const;
|
||||
|
||||
Reference in New Issue
Block a user