mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-03 14:09:33 +03:00
Vulkan: Move default uniform init to link job
Bug: angleproject:8297 Change-Id: I5bab916f452439d92afa65b9172574000ee0b587 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4762838 Reviewed-by: Charlie Lao <cclao@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Yuxin Hu <yuxinhu@google.com>
This commit is contained in:
committed by
Angle LUCI CQ
parent
f4e5c327d7
commit
d8cd4dcdc9
@@ -1122,7 +1122,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)
|
||||
{
|
||||
@@ -6152,7 +6152,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)
|
||||
{
|
||||
|
||||
@@ -1056,8 +1056,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);
|
||||
|
||||
|
||||
@@ -452,7 +452,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;
|
||||
|
||||
|
||||
@@ -263,6 +263,47 @@ class Shader final : angle::NonCopyable, public LabeledObject
|
||||
const std::vector<sh::ShaderVariable> &getAllAttributes(const Context *context);
|
||||
const std::vector<sh::ShaderVariable> &getActiveOutputVariables(const Context *context);
|
||||
|
||||
const std::vector<sh::ShaderVariable> &getInputVaryingsCompiled()
|
||||
{
|
||||
ASSERT(!mState.compilePending());
|
||||
return mState.getInputVaryings();
|
||||
}
|
||||
const std::vector<sh::ShaderVariable> &getOutputVaryingsCompiled()
|
||||
{
|
||||
ASSERT(!mState.compilePending());
|
||||
return mState.getOutputVaryings();
|
||||
}
|
||||
const std::vector<sh::ShaderVariable> &getUniformsCompiled()
|
||||
{
|
||||
ASSERT(!mState.compilePending());
|
||||
return mState.getUniforms();
|
||||
}
|
||||
const std::vector<sh::InterfaceBlock> &getUniformBlocksCompiled()
|
||||
{
|
||||
ASSERT(!mState.compilePending());
|
||||
return mState.getUniformBlocks();
|
||||
}
|
||||
const std::vector<sh::InterfaceBlock> &getShaderStorageBlocksCompiled()
|
||||
{
|
||||
ASSERT(!mState.compilePending());
|
||||
return mState.getShaderStorageBlocks();
|
||||
}
|
||||
const std::vector<sh::ShaderVariable> &getActiveAttributesCompiled()
|
||||
{
|
||||
ASSERT(!mState.compilePending());
|
||||
return mState.getActiveAttributes();
|
||||
}
|
||||
const std::vector<sh::ShaderVariable> &getAllAttributesCompiled()
|
||||
{
|
||||
ASSERT(!mState.compilePending());
|
||||
return mState.getAllAttributes();
|
||||
}
|
||||
const std::vector<sh::ShaderVariable> &getActiveOutputVariablesCompiled()
|
||||
{
|
||||
ASSERT(!mState.compilePending());
|
||||
return mState.getActiveOutputVariables();
|
||||
}
|
||||
|
||||
// Returns mapped name of a transform feedback varying. The original name may contain array
|
||||
// brackets with an index inside, which will get copied to the mapped name. The varying must be
|
||||
// known to be declared in the shader.
|
||||
|
||||
@@ -1863,7 +1863,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)
|
||||
{
|
||||
@@ -1874,7 +1874,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,17 +22,37 @@ 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,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks,
|
||||
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,
|
||||
gl::ScopedShaderLinkLocks *shaderLocks,
|
||||
bool isGLES1,
|
||||
vk::PipelineRobustness pipelineRobustness,
|
||||
vk::PipelineProtectedAccess pipelineProtectedAccess)
|
||||
: vk::Context(renderer),
|
||||
mState(state),
|
||||
mGlExecutable(glExecutable),
|
||||
@@ -44,7 +64,11 @@ class LinkTask final : public vk::Context, public angle::Closure
|
||||
mShaderLocks.swap(*shaderLocks);
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -81,6 +105,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;
|
||||
@@ -101,14 +132,16 @@ 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");
|
||||
|
||||
// Unlock the shaders at the end of the task.
|
||||
gl::ScopedShaderLinkLocks unlockAtEnd;
|
||||
unlockAtEnd.swap(mShaderLocks);
|
||||
|
||||
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.
|
||||
//
|
||||
@@ -121,60 +154,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,
|
||||
@@ -202,6 +202,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())
|
||||
{
|
||||
gl::Shader *shader = mState.getAttachedShader(shaderType);
|
||||
|
||||
if (shader)
|
||||
{
|
||||
const std::vector<sh::ShaderVariable> &uniforms = shader->getUniformsCompiled();
|
||||
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,
|
||||
@@ -322,6 +413,18 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVk::link");
|
||||
|
||||
// Make sure no compile jobs are pending.
|
||||
// TODO: move this to the link job itself. http://anglebug.com/8297
|
||||
const gl::ProgramExecutable &programExecutable = mState.getExecutable();
|
||||
for (const gl::ShaderType shaderType : programExecutable.getLinkedShaderStages())
|
||||
{
|
||||
gl::Shader *shader = mState.getAttachedShader(shaderType);
|
||||
if (shader)
|
||||
{
|
||||
shader->resolveCompile(context);
|
||||
}
|
||||
}
|
||||
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
// Link resources before calling GetShaderSource to make sure they are ready for the set/binding
|
||||
// assignment done in that function.
|
||||
@@ -343,8 +446,7 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
|
||||
}
|
||||
|
||||
// Compile the shaders.
|
||||
const gl::ProgramExecutable &programExecutable = mState.getExecutable();
|
||||
angle::Result status = mExecutable.mOriginalShaderInfo.initShaders(
|
||||
angle::Result status = mExecutable.mOriginalShaderInfo.initShaders(
|
||||
contextVk, programExecutable.getLinkedShaderStages(), spirvBlobs,
|
||||
mExecutable.mVariableInfoMap);
|
||||
if (status != angle::Result::Continue)
|
||||
@@ -352,21 +454,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, shaderLocks,
|
||||
context->getState().isGLES1(), contextVk->pipelineRobustness(),
|
||||
contextVk->pipelineProtectedAccess());
|
||||
@@ -382,91 +476,6 @@ void ProgramVk::linkResources(const gl::Context *context,
|
||||
linker.linkResources(context, 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(glContext, 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(const gl::Context *context,
|
||||
gl::ShaderMap<sh::BlockLayoutMap> &layoutMap,
|
||||
gl::ShaderMap<size_t> &requiredBufferSize)
|
||||
{
|
||||
const gl::ProgramExecutable &glExecutable = mState.getExecutable();
|
||||
|
||||
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
|
||||
{
|
||||
gl::Shader *shader = mState.getAttachedShader(shaderType);
|
||||
|
||||
if (shader)
|
||||
{
|
||||
const std::vector<sh::ShaderVariable> &uniforms = shader->getUniforms(context);
|
||||
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.
|
||||
|
||||
@@ -128,11 +128,6 @@ class ProgramVk : public ProgramImpl
|
||||
const GLfloat *value);
|
||||
|
||||
void reset(ContextVk *contextVk);
|
||||
angle::Result initDefaultUniformBlocks(const gl::Context *glContext);
|
||||
void generateUniformLayoutMapping(const gl::Context *context,
|
||||
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;
|
||||
|
||||
@@ -27,6 +27,12 @@ class LinkAndRelinkTestES31 : public ANGLETest<>
|
||||
LinkAndRelinkTestES31() {}
|
||||
};
|
||||
|
||||
class LinkAndRelinkTestES32 : public ANGLETest<>
|
||||
{
|
||||
protected:
|
||||
LinkAndRelinkTestES32() {}
|
||||
};
|
||||
|
||||
// When a program link or relink fails, if you try to install the unsuccessfully
|
||||
// linked program (via UseProgram) and start rendering or dispatch compute,
|
||||
// We can not always report INVALID_OPERATION for rendering/compute pipeline.
|
||||
@@ -445,6 +451,130 @@ void main()
|
||||
EXPECT_GL_NO_ERROR();
|
||||
}
|
||||
|
||||
// Parallel link should continue unscathed even if the attached shaders to the program are modified.
|
||||
TEST_P(LinkAndRelinkTestES31, ReattachShadersWhileParallelLinking)
|
||||
{
|
||||
constexpr char kVS[] = R"(#version 300 es
|
||||
void main()
|
||||
{
|
||||
vec2 position = vec2(-1, -1);
|
||||
if (gl_VertexID == 1)
|
||||
position = vec2(3, -1);
|
||||
else if (gl_VertexID == 2)
|
||||
position = vec2(-1, 3);
|
||||
gl_Position = vec4(position, 0, 1);
|
||||
})";
|
||||
constexpr char kFSGreen[] = R"(#version 300 es
|
||||
out mediump vec4 color;
|
||||
void main()
|
||||
{
|
||||
color = vec4(0, 1, 0, 1);
|
||||
})";
|
||||
constexpr char kFSRed[] = R"(#version 300 es
|
||||
out mediump vec4 color;
|
||||
void main()
|
||||
{
|
||||
color = vec4(1, 0, 0, 1);
|
||||
})";
|
||||
|
||||
GLuint program = glCreateProgram();
|
||||
|
||||
GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
|
||||
GLuint green = CompileShader(GL_FRAGMENT_SHADER, kFSGreen);
|
||||
GLuint red = CompileShader(GL_FRAGMENT_SHADER, kFSRed);
|
||||
|
||||
EXPECT_NE(0u, vs);
|
||||
EXPECT_NE(0u, green);
|
||||
EXPECT_NE(0u, red);
|
||||
|
||||
glAttachShader(program, vs);
|
||||
glAttachShader(program, green);
|
||||
glLinkProgram(program);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
// Immediately reattach another shader
|
||||
glDetachShader(program, green);
|
||||
glAttachShader(program, red);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
// Make sure the linked program draws with green
|
||||
glUseProgram(program);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
glDeleteShader(vs);
|
||||
glDeleteShader(green);
|
||||
glDeleteShader(red);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
}
|
||||
|
||||
// Parallel link should continue unscathed even if new shaders are attached to the program.
|
||||
TEST_P(LinkAndRelinkTestES31, AttachNewShadersWhileParallelLinking)
|
||||
{
|
||||
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_geometry_shader"));
|
||||
|
||||
constexpr char kVS[] = R"(#version 310 es
|
||||
#extension GL_EXT_geometry_shader : require
|
||||
void main()
|
||||
{
|
||||
vec2 position = vec2(-1, -1);
|
||||
if (gl_VertexID == 1)
|
||||
position = vec2(3, -1);
|
||||
else if (gl_VertexID == 2)
|
||||
position = vec2(-1, 3);
|
||||
gl_Position = vec4(position, 0, 1);
|
||||
})";
|
||||
constexpr char kFS[] = R"(#version 310 es
|
||||
#extension GL_EXT_geometry_shader : require
|
||||
out mediump vec4 color;
|
||||
void main()
|
||||
{
|
||||
color = vec4(0, 1, 0, 1);
|
||||
})";
|
||||
constexpr char kGS[] = R"(#version 310 es
|
||||
#extension GL_EXT_geometry_shader : require
|
||||
layout (invocations = 3, triangles) in;
|
||||
layout (triangle_strip, max_vertices = 3) out;
|
||||
void main()
|
||||
{
|
||||
})";
|
||||
|
||||
GLuint program = glCreateProgram();
|
||||
|
||||
GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
|
||||
GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
|
||||
GLuint gs = CompileShader(GL_GEOMETRY_SHADER, kGS);
|
||||
|
||||
EXPECT_NE(0u, vs);
|
||||
EXPECT_NE(0u, fs);
|
||||
EXPECT_NE(0u, gs);
|
||||
|
||||
glAttachShader(program, vs);
|
||||
glAttachShader(program, fs);
|
||||
glLinkProgram(program);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
// Immediately attach another shader
|
||||
glAttachShader(program, gs);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
// Make sure the linked program draws with green
|
||||
glUseProgram(program);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
glDeleteShader(vs);
|
||||
glDeleteShader(fs);
|
||||
glDeleteShader(gs);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
}
|
||||
|
||||
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(LinkAndRelinkTest);
|
||||
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LinkAndRelinkTestES31);
|
||||
|
||||
Reference in New Issue
Block a user