Vulkan: Store ProgramVk shaders in ShaderInfo.
This encapsulates most of the logic for a Program into a helper class.
Now we can store multiple instances of the Program's back-end to
implement different shader behaviour at draw time.
This will be useful for shader patching for OpenGL line segment raster.
Bug: angleproject:2598
Change-Id: I800a737088574e28f3a4ec23b91c0cb2647e4e12
Reviewed-on: https://chromium-review.googlesource.com/1127302
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/ProgramVk.cpp b/src/libANGLE/renderer/vulkan/ProgramVk.cpp
index 07be0bd..15fa0ed 100644
--- a/src/libANGLE/renderer/vulkan/ProgramVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ProgramVk.cpp
@@ -26,13 +26,11 @@
constexpr size_t kUniformBlockDynamicBufferMinSize = 256 * 128;
-void InitDefaultUniformBlock(const gl::Context *context,
+void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms,
gl::Shader *shader,
sh::BlockLayoutMap *blockLayoutMapOut,
size_t *blockSizeOut)
{
- const auto &uniforms = shader->getUniforms(context);
-
if (uniforms.empty())
{
*blockSizeOut = 0;
@@ -132,37 +130,70 @@
}
} // anonymous namespace
+// ProgramVk::ShaderInfo implementation.
+ProgramVk::ShaderInfo::ShaderInfo()
+{
+}
+
+ProgramVk::ShaderInfo::~ShaderInfo() = default;
+
+angle::Result ProgramVk::ShaderInfo::getShaders(
+ ContextVk *contextVk,
+ const std::string &vertexSource,
+ const std::string &fragmentSource,
+ const vk::ShaderAndSerial **vertexShaderAndSerialOut,
+ const vk::ShaderAndSerial **fragmentShaderAndSerialOut)
+{
+ if (!valid())
+ {
+ std::vector<uint32_t> vertexCode;
+ std::vector<uint32_t> fragmentCode;
+ ANGLE_TRY(GlslangWrapper::GetShaderCode(contextVk, contextVk->getCaps(), vertexSource,
+ fragmentSource, &vertexCode, &fragmentCode));
+
+ ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mVertexShaderAndSerial, vertexCode.data(),
+ vertexCode.size() * sizeof(uint32_t)));
+ ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mFragmentShaderAndSerial, fragmentCode.data(),
+ fragmentCode.size() * sizeof(uint32_t)));
+ }
+
+ *fragmentShaderAndSerialOut = &mFragmentShaderAndSerial;
+ *vertexShaderAndSerialOut = &mVertexShaderAndSerial;
+ return angle::Result::Continue();
+}
+
+void ProgramVk::ShaderInfo::destroy(VkDevice device)
+{
+ mVertexShaderAndSerial.destroy(device);
+ mFragmentShaderAndSerial.destroy(device);
+}
+
+bool ProgramVk::ShaderInfo::valid() const
+{
+ return mVertexShaderAndSerial.valid();
+}
+
+// ProgramVk implementation.
ProgramVk::DefaultUniformBlock::DefaultUniformBlock()
: storage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
kUniformBlockDynamicBufferMinSize),
- uniformData(),
- uniformsDirty(false),
- uniformLayout()
+ uniformsDirty(false)
{
}
-ProgramVk::DefaultUniformBlock::~DefaultUniformBlock()
-{
-}
+ProgramVk::DefaultUniformBlock::~DefaultUniformBlock() = default;
ProgramVk::ProgramVk(const gl::ProgramState &state)
- : ProgramImpl(state),
- mDefaultUniformBlocks(),
- mUniformBlocksOffsets(),
- mUsedDescriptorSetRange(),
- mDirtyTextures(true)
+ : ProgramImpl(state), mUniformBlocksOffsets{}, mDirtyTextures(false)
{
- mUniformBlocksOffsets.fill(0);
mUsedDescriptorSetRange.invalidate();
}
-ProgramVk::~ProgramVk()
-{
-}
+ProgramVk::~ProgramVk() = default;
-gl::Error ProgramVk::destroy(const gl::Context *contextImpl)
+gl::Error ProgramVk::destroy(const gl::Context *context)
{
- ContextVk *contextVk = vk::GetImpl(contextImpl);
+ ContextVk *contextVk = vk::GetImpl(context);
return reset(contextVk);
}
@@ -182,13 +213,13 @@
uniformBlock.storage.release(renderer);
}
+ // TODO(jmadill): Line rasterization emulation shaders. http://anglebug.com/2598
+ mDefaultShaderInfo.destroy(device);
+
Serial currentSerial = renderer->getCurrentQueueSerial();
renderer->releaseObject(currentSerial, &mEmptyUniformBlockStorage.memory);
renderer->releaseObject(currentSerial, &mEmptyUniformBlockStorage.buffer);
- mDefaultVertexShaderAndSerial.destroy(device);
- mDefaultFragmentShaderAndSerial.destroy(device);
-
mDescriptorSets.clear();
mUsedDescriptorSetRange.invalidate();
mDirtyTextures = false;
@@ -196,7 +227,7 @@
return angle::Result::Continue();
}
-gl::LinkResult ProgramVk::load(const gl::Context *contextImpl,
+gl::LinkResult ProgramVk::load(const gl::Context *context,
gl::InfoLog &infoLog,
gl::BinaryInputStream *stream)
{
@@ -228,25 +259,7 @@
ANGLE_TRY(reset(contextVk));
- std::string vertexSource;
- std::string fragmentSource;
- GlslangWrapper::GetShaderSource(glContext, mState, resources, &vertexSource, &fragmentSource);
-
- std::vector<uint32_t> vertexCode;
- std::vector<uint32_t> fragmentCode;
- bool linkSuccess = false;
- ANGLE_TRY_RESULT(GlslangWrapper::GetShaderCode(glContext->getCaps(), vertexSource,
- fragmentSource, &vertexCode, &fragmentCode),
- linkSuccess);
- if (!linkSuccess)
- {
- return false;
- }
-
- ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mDefaultVertexShaderAndSerial, vertexCode.data(),
- vertexCode.size() * sizeof(uint32_t)));
- ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mDefaultFragmentShaderAndSerial,
- fragmentCode.data(), fragmentCode.size() * sizeof(uint32_t)));
+ GlslangWrapper::GetShaderSource(glContext, mState, resources, &mVertexSource, &mFragmentSource);
ANGLE_TRY(initDefaultUniformBlocks(glContext));
@@ -298,10 +311,28 @@
ANGLE_TRY(renderer->getPipelineLayout(contextVk, pipelineLayoutDesc, mDescriptorSetLayouts,
&mPipelineLayout));
+ if (!mState.getUniforms().empty())
+ {
+ const gl::RangeUI &samplerRange = mState.getSamplerUniformRange();
+
+ if (mState.getUniforms().size() > samplerRange.length())
+ {
+ // Ensure the descriptor set range includes the uniform buffers at position 0.
+ mUsedDescriptorSetRange.extend(kUniformsDescriptorSetIndex);
+ }
+
+ if (!samplerRange.empty())
+ {
+ // Ensure the descriptor set range includes the textures at position 1.
+ mUsedDescriptorSetRange.extend(kTextureDescriptorSetIndex);
+ mDirtyTextures = true;
+ }
+ }
+
return true;
}
-gl::Error ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
+angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
{
ContextVk *contextVk = vk::GetImpl(glContext);
RendererVk *renderer = contextVk->getRenderer();
@@ -314,18 +345,18 @@
for (vk::ShaderType shaderType : vk::AllShaderTypes())
{
gl::ShaderType glShaderType = static_cast<gl::ShaderType>(shaderType);
- InitDefaultUniformBlock(glContext, mState.getAttachedShader(glShaderType),
- &layoutMap[shaderType], &requiredBufferSize[shaderType]);
+ gl::Shader *shader = mState.getAttachedShader(glShaderType);
+ const std::vector<sh::Uniform> &uniforms = shader->getUniforms(glContext);
+ InitDefaultUniformBlock(uniforms, shader, &layoutMap[shaderType],
+ &requiredBufferSize[shaderType]);
}
// Init the default block layout info.
- const auto &locations = mState.getUniformLocations();
const auto &uniforms = mState.getUniforms();
- for (size_t locationIndex = 0; locationIndex < locations.size(); ++locationIndex)
+ for (const gl::VariableLocation &location : mState.getUniformLocations())
{
vk::ShaderMap<sh::BlockMemberInfo> layoutInfo;
- const auto &location = locations[locationIndex];
if (location.used() && !location.ignored)
{
const auto &uniform = uniforms[location.index];
@@ -371,7 +402,7 @@
if (!mDefaultUniformBlocks[shaderType].uniformData.resize(
requiredBufferSize[shaderType]))
{
- return gl::OutOfMemory() << "Memory allocation failure.";
+ ANGLE_VK_CHECK(contextVk, false, VK_ERROR_OUT_OF_HOST_MEMORY);
}
size_t minAlignment = static_cast<size_t>(
renderer->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment);
@@ -413,12 +444,9 @@
ANGLE_TRY(AllocateBufferMemory(contextVk, flags, &mEmptyUniformBlockStorage.buffer,
&mEmptyUniformBlockStorage.memory));
}
-
- // Ensure the descriptor set range includes the uniform buffers at position 0.
- mUsedDescriptorSetRange.extend(0);
}
- return gl::NoError();
+ return angle::Result::Continue();
}
GLboolean ProgramVk::validate(const gl::Caps &caps, gl::InfoLog *infoLog)
@@ -699,18 +727,20 @@
UNIMPLEMENTED();
}
-gl::Error ProgramVk::initShaders(const ContextVk *contextVk,
- const gl::DrawCallParams &drawCallParams,
- const vk::ShaderAndSerial **vertexShaderAndSerialOut,
- const vk::ShaderAndSerial **fragmentShaderAndSerialOut)
+angle::Result ProgramVk::initShaders(ContextVk *contextVk,
+ const gl::DrawCallParams &drawCallParams,
+ const vk::ShaderAndSerial **vertexShaderAndSerialOut,
+ const vk::ShaderAndSerial **fragmentShaderAndSerialOut,
+ const vk::PipelineLayout **pipelineLayoutOut)
{
- // TODO(jmadill): Move more init into this method. http://anglebug.com/2598
// TODO(jmadill): Line rasterization emulation shaders. http://anglebug.com/2598
- ASSERT(mDefaultVertexShaderAndSerial.valid());
- ASSERT(mDefaultFragmentShaderAndSerial.valid());
- *vertexShaderAndSerialOut = &mDefaultVertexShaderAndSerial;
- *fragmentShaderAndSerialOut = &mDefaultFragmentShaderAndSerial;
- return gl::NoError();
+ ANGLE_TRY(mDefaultShaderInfo.getShaders(contextVk, mVertexSource, mFragmentSource,
+ vertexShaderAndSerialOut, fragmentShaderAndSerialOut));
+ ASSERT(mDefaultShaderInfo.valid());
+
+ *pipelineLayoutOut = &mPipelineLayout.get();
+
+ return angle::Result::Continue();
}
angle::Result ProgramVk::allocateDescriptorSet(ContextVk *contextVk, uint32_t descriptorSetIndex)
@@ -755,10 +785,7 @@
return angle::Result::Continue();
}
- ASSERT(mUsedDescriptorSetRange.contains(0));
-
// Update buffer memory by immediate mapping. This immediate update only works once.
- // TODO(jmadill): Handle inserting updates into the command stream, or use dynamic buffers.
bool anyNewBufferAllocated = false;
for (vk::ShaderType shaderType : vk::AllShaderTypes())
{
@@ -797,9 +824,9 @@
for (vk::ShaderType shaderType : vk::AllShaderTypes())
{
- auto &uniformBlock = mDefaultUniformBlocks[shaderType];
- auto &bufferInfo = descriptorBufferInfo[shaderType];
- auto &writeInfo = writeDescriptorInfo[shaderType];
+ DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
+ VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[shaderType];
+ VkWriteDescriptorSet &writeInfo = writeDescriptorInfo[shaderType];
if (!uniformBlock.uniformData.empty())
{
@@ -832,34 +859,6 @@
return angle::Result::Continue();
}
-const std::vector<VkDescriptorSet> &ProgramVk::getDescriptorSets() const
-{
- return mDescriptorSets;
-}
-
-const uint32_t *ProgramVk::getDynamicOffsets()
-{
- // If we have no descriptor set being used, we do not need to specify any offsets when binding
- // the descriptor sets.
- if (!mUsedDescriptorSetRange.contains(0))
- return nullptr;
-
- return mUniformBlocksOffsets.data();
-}
-
-uint32_t ProgramVk::getDynamicOffsetsCount()
-{
- if (!mUsedDescriptorSetRange.contains(0))
- return 0;
-
- return static_cast<uint32_t>(mUniformBlocksOffsets.size());
-}
-
-const gl::RangeUI &ProgramVk::getUsedDescriptorSetRange() const
-{
- return mUsedDescriptorSetRange;
-}
-
angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk)
{
if (mState.getSamplerBindings().empty() || !mDirtyTextures)
@@ -929,11 +928,6 @@
mDirtyTextures = true;
}
-const vk::PipelineLayout &ProgramVk::getPipelineLayout() const
-{
- return mPipelineLayout.get();
-}
-
void ProgramVk::setDefaultUniformBlocksMinSizeForTesting(size_t minSize)
{
for (DefaultUniformBlock &block : mDefaultUniformBlocks)
@@ -941,4 +935,43 @@
block.storage.setMinimumSizeForTesting(minSize);
}
}
+
+angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk,
+ const gl::DrawCallParams &drawCallParams,
+ VkDescriptorSet driverUniformsDescriptorSet,
+ vk::CommandBuffer *commandBuffer)
+{
+ // TODO(jmadill): Line rasterization emulation shaders. http://anglebug.com/2598
+ // Can probably use better dirty bits here.
+ ANGLE_TRY(updateUniforms(contextVk));
+ ANGLE_TRY(updateTexturesDescriptorSet(contextVk));
+
+ commandBuffer->bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, mPipelineLayout.get(),
+ kDriverUniformsDescriptorSetIndex, 1,
+ &driverUniformsDescriptorSet, 0, nullptr);
+
+ if (mUsedDescriptorSetRange.empty())
+ return angle::Result::Continue();
+
+ ASSERT(!mDescriptorSets.empty());
+
+ unsigned int low = mUsedDescriptorSetRange.low();
+
+ // No uniforms descriptor set means no need to specify dynamic buffer offsets.
+ if (mUsedDescriptorSetRange.contains(kUniformsDescriptorSetIndex))
+ {
+ commandBuffer->bindDescriptorSets(
+ VK_PIPELINE_BIND_POINT_GRAPHICS, mPipelineLayout.get(), low,
+ mUsedDescriptorSetRange.length(), &mDescriptorSets[low],
+ static_cast<uint32_t>(mUniformBlocksOffsets.size()), mUniformBlocksOffsets.data());
+ }
+ else
+ {
+ commandBuffer->bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, mPipelineLayout.get(),
+ low, mUsedDescriptorSetRange.length(),
+ &mDescriptorSets[low], 0, nullptr);
+ }
+
+ return angle::Result::Continue();
+}
} // namespace rx