Commit 054aeeed by Charlie Lao Committed by Commit Bot

Vulkan: Batch vkUpdateDescriptorSets calls

Right now we are making this calls multiple times as we loop through each shader stage. Qualcomm performance validation layer warns about this. This change will aggregate the calls into one call per dispatch. Bug: b/158787299 Change-Id: I48aa3752f708c26ffbca2fb7947cb8bbc0f76dcd Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2243321 Commit-Queue: Charlie Lao <cclao@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 70e706f4
...@@ -47,6 +47,12 @@ namespace rx ...@@ -47,6 +47,12 @@ namespace rx
namespace namespace
{ {
// For DesciptorSetUpdates
constexpr size_t kDescriptorBufferInfosInitialSize = 8;
constexpr size_t kDescriptorImageInfosInitialSize = 4;
constexpr size_t kDescriptorWriteInfosInitialSize =
kDescriptorBufferInfosInitialSize + kDescriptorImageInfosInitialSize;
// For shader uniforms such as gl_DepthRange and the viewport size. // For shader uniforms such as gl_DepthRange and the viewport size.
struct GraphicsDriverUniforms struct GraphicsDriverUniforms
{ {
...@@ -620,7 +626,10 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -620,7 +626,10 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mPrimaryBufferCounter(0), mPrimaryBufferCounter(0),
mRenderPassCounter(0), mRenderPassCounter(0),
mContextPriority(renderer->getDriverPriority(GetContextPriority(state))), mContextPriority(renderer->getDriverPriority(GetContextPriority(state))),
mCurrentIndirectBuffer(nullptr) mCurrentIndirectBuffer(nullptr),
mBufferInfos(),
mImageInfos(),
mWriteInfos()
{ {
ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::ContextVk"); ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::ContextVk");
memset(&mClearColorValue, 0, sizeof(mClearColorValue)); memset(&mClearColorValue, 0, sizeof(mClearColorValue));
...@@ -709,6 +718,11 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -709,6 +718,11 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mPipelineDirtyBitsMask.set(); mPipelineDirtyBitsMask.set();
mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_TEXTURE_BINDINGS); mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_TEXTURE_BINDINGS);
// Reserve reasonable amount of spaces so that for majority of apps we don't need to grow at all
mBufferInfos.reserve(kDescriptorBufferInfosInitialSize);
mImageInfos.reserve(kDescriptorImageInfosInitialSize);
mWriteInfos.reserve(kDescriptorWriteInfosInitialSize);
} }
ContextVk::~ContextVk() = default; ContextVk::~ContextVk() = default;
...@@ -935,6 +949,10 @@ angle::Result ContextVk::setupDraw(const gl::Context *context, ...@@ -935,6 +949,10 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
*commandBufferOut = mRenderPassCommandBuffer; *commandBufferOut = mRenderPassCommandBuffer;
ASSERT(*commandBufferOut); ASSERT(*commandBufferOut);
// Create a local object to ensure we flush the descriptor updates to device when we leave this
// function
ScopedDescriptorSetUpdates descriptorSetUpdates(this);
if (mProgram && mProgram->dirtyUniforms()) if (mProgram && mProgram->dirtyUniforms())
{ {
ANGLE_TRY(mProgram->updateUniforms(this)); ANGLE_TRY(mProgram->updateUniforms(this));
...@@ -1163,6 +1181,10 @@ angle::Result ContextVk::setupDispatch(const gl::Context *context, ...@@ -1163,6 +1181,10 @@ angle::Result ContextVk::setupDispatch(const gl::Context *context,
ANGLE_TRY(endRenderPass()); ANGLE_TRY(endRenderPass());
*commandBufferOut = &mOutsideRenderPassCommands->getCommandBuffer(); *commandBufferOut = &mOutsideRenderPassCommands->getCommandBuffer();
// Create a local object to ensure we flush the descriptor updates to device when we leave this
// function
ScopedDescriptorSetUpdates descriptorSetUpdates(this);
if (mProgram && mProgram->dirtyUniforms()) if (mProgram && mProgram->dirtyUniforms())
{ {
ANGLE_TRY(mProgram->updateUniforms(this)); ANGLE_TRY(mProgram->updateUniforms(this));
...@@ -3600,23 +3622,21 @@ angle::Result ContextVk::updateDriverUniformsDescriptorSet( ...@@ -3600,23 +3622,21 @@ angle::Result ContextVk::updateDriverUniformsDescriptorSet(
&driverUniforms->descriptorPoolBinding, &driverUniforms->descriptorSet)); &driverUniforms->descriptorPoolBinding, &driverUniforms->descriptorSet));
// Update the driver uniform descriptor set. // Update the driver uniform descriptor set.
VkDescriptorBufferInfo bufferInfo = {}; VkDescriptorBufferInfo &bufferInfo = allocBufferInfo();
bufferInfo.buffer = buffer; bufferInfo.buffer = buffer;
bufferInfo.offset = 0; bufferInfo.offset = 0;
bufferInfo.range = driverUniformsSize; bufferInfo.range = driverUniformsSize;
VkWriteDescriptorSet writeInfo = {}; VkWriteDescriptorSet &writeInfo = allocWriteInfo();
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeInfo.dstSet = driverUniforms->descriptorSet; writeInfo.dstSet = driverUniforms->descriptorSet;
writeInfo.dstBinding = 0; writeInfo.dstBinding = 0;
writeInfo.dstArrayElement = 0; writeInfo.dstArrayElement = 0;
writeInfo.descriptorCount = 1; writeInfo.descriptorCount = 1;
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
writeInfo.pImageInfo = nullptr; writeInfo.pImageInfo = nullptr;
writeInfo.pTexelBufferView = nullptr; writeInfo.pTexelBufferView = nullptr;
writeInfo.pBufferInfo = &bufferInfo; writeInfo.pBufferInfo = &bufferInfo;
vkUpdateDescriptorSets(getDevice(), 1, &writeInfo, 0, nullptr);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -4474,4 +4494,74 @@ bool ContextVk::isRobustResourceInitEnabled() const ...@@ -4474,4 +4494,74 @@ bool ContextVk::isRobustResourceInitEnabled() const
return mState.isRobustResourceInitEnabled(); return mState.isRobustResourceInitEnabled();
} }
VkDescriptorBufferInfo &ContextVk::allocBufferInfos(size_t count)
{
return allocInfos<VkDescriptorBufferInfo, &VkWriteDescriptorSet::pBufferInfo>(&mBufferInfos,
count);
}
VkDescriptorImageInfo &ContextVk::allocImageInfos(size_t count)
{
return allocInfos<VkDescriptorImageInfo, &VkWriteDescriptorSet::pImageInfo>(&mImageInfos,
count);
}
template <typename T, const T *VkWriteDescriptorSet::*pInfo>
T &ContextVk::allocInfos(std::vector<T> *mInfos, size_t count)
{
size_t oldSize = mInfos->size();
size_t newSize = oldSize + count;
if (newSize > mInfos->capacity())
{
// If we have reached capacity, grow the storage and patch the descriptor set with new
// buffer info pointer
growCapacity<T, pInfo>(mInfos, newSize);
}
mInfos->resize(newSize);
return (*mInfos)[oldSize];
}
template <typename T, const T *VkWriteDescriptorSet::*pInfo>
void ContextVk::growCapacity(std::vector<T> *mInfos, size_t newSize)
{
const T *const oldInfoStart = mInfos->empty() ? nullptr : &(*mInfos)[0];
size_t newCapacity = std::max(mInfos->capacity() << 1, newSize);
mInfos->reserve(newCapacity);
if (oldInfoStart)
{
// patch mWriteInfo with new BufferInfo/ImageInfo pointers
for (VkWriteDescriptorSet &set : mWriteInfos)
{
if (set.*pInfo)
{
size_t index = set.*pInfo - oldInfoStart;
set.*pInfo = &(*mInfos)[index];
}
}
}
}
// ScopedDescriptorSetUpdates
ANGLE_INLINE ContextVk::ScopedDescriptorSetUpdates::ScopedDescriptorSetUpdates(ContextVk *contextVk)
: mContextVk(contextVk)
{}
ANGLE_INLINE ContextVk::ScopedDescriptorSetUpdates::~ScopedDescriptorSetUpdates()
{
if (mContextVk->mWriteInfos.empty())
{
ASSERT(mContextVk->mBufferInfos.empty());
ASSERT(mContextVk->mImageInfos.empty());
return;
}
vkUpdateDescriptorSets(mContextVk->getDevice(),
static_cast<uint32_t>(mContextVk->mWriteInfos.size()),
mContextVk->mWriteInfos.data(), 0, nullptr);
mContextVk->mWriteInfos.clear();
mContextVk->mBufferInfos.clear();
mContextVk->mImageInfos.clear();
}
} // namespace rx } // namespace rx
...@@ -526,6 +526,20 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -526,6 +526,20 @@ class ContextVk : public ContextImpl, public vk::Context
// When worker thread completes, it releases command buffers back to context queue // When worker thread completes, it releases command buffers back to context queue
void recycleCommandBuffer(vk::CommandBufferHelper *commandBuffer); void recycleCommandBuffer(vk::CommandBufferHelper *commandBuffer);
// DescriptorSet writes
VkDescriptorBufferInfo &allocBufferInfo() { return allocBufferInfos(1); }
VkDescriptorBufferInfo &allocBufferInfos(size_t count);
VkDescriptorImageInfo &allocImageInfo() { return allocImageInfos(1); }
VkDescriptorImageInfo &allocImageInfos(size_t count);
VkWriteDescriptorSet &allocWriteInfo() { return allocWriteInfos(1); }
VkWriteDescriptorSet &allocWriteInfos(size_t count)
{
size_t oldSize = mWriteInfos.size();
size_t newSize = oldSize + count;
mWriteInfos.resize(newSize);
return mWriteInfos[oldSize];
}
private: private:
// Dirty bits. // Dirty bits.
enum DirtyBitType : size_t enum DirtyBitType : size_t
...@@ -616,6 +630,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -616,6 +630,7 @@ class ContextVk : public ContextImpl, public vk::Context
const void *indices, const void *indices,
DirtyBits dirtyBitMask, DirtyBits dirtyBitMask,
vk::CommandBuffer **commandBufferOut); vk::CommandBuffer **commandBufferOut);
angle::Result setupIndexedDraw(const gl::Context *context, angle::Result setupIndexedDraw(const gl::Context *context,
gl::PrimitiveMode mode, gl::PrimitiveMode mode,
GLsizei indexCount, GLsizei indexCount,
...@@ -800,6 +815,12 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -800,6 +815,12 @@ class ContextVk : public ContextImpl, public vk::Context
size_t bufferCount, size_t bufferCount,
const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers); const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers);
// DescriptorSet writes
template <typename T, const T *VkWriteDescriptorSet::*pInfo>
T &allocInfos(std::vector<T> *mInfos, size_t count);
template <typename T, const T *VkWriteDescriptorSet::*pInfo>
void growCapacity(std::vector<T> *mInfos, size_t newSize);
std::array<DirtyBitHandler, DIRTY_BIT_MAX> mGraphicsDirtyBitHandlers; std::array<DirtyBitHandler, DIRTY_BIT_MAX> mGraphicsDirtyBitHandlers;
std::array<DirtyBitHandler, DIRTY_BIT_MAX> mComputeDirtyBitHandlers; std::array<DirtyBitHandler, DIRTY_BIT_MAX> mComputeDirtyBitHandlers;
...@@ -976,6 +997,20 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -976,6 +997,20 @@ class ContextVk : public ContextImpl, public vk::Context
const vk::BufferHelper *mCurrentIndirectBuffer; const vk::BufferHelper *mCurrentIndirectBuffer;
// Storage for vkUpdateDescriptorSets
std::vector<VkDescriptorBufferInfo> mBufferInfos;
std::vector<VkDescriptorImageInfo> mImageInfos;
std::vector<VkWriteDescriptorSet> mWriteInfos;
class ScopedDescriptorSetUpdates final : angle::NonCopyable
{
public:
ScopedDescriptorSetUpdates(ContextVk *contextVk);
~ScopedDescriptorSetUpdates();
private:
ContextVk *mContextVk;
};
std::vector<std::string> mCommandBufferDiagnostics; std::vector<std::string> mCommandBufferDiagnostics;
}; };
......
...@@ -193,7 +193,7 @@ void TransformFeedbackVk::initDescriptorSet(ContextVk *contextVk, ...@@ -193,7 +193,7 @@ void TransformFeedbackVk::initDescriptorSet(ContextVk *contextVk,
if (!contextVk->getFeatures().emulateTransformFeedback.enabled) if (!contextVk->getFeatures().emulateTransformFeedback.enabled)
return; return;
gl::TransformFeedbackBuffersArray<VkDescriptorBufferInfo> descriptorBufferInfo; VkDescriptorBufferInfo *descriptorBufferInfo = &contextVk->allocBufferInfos(xfbBufferCount);
for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex) for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
{ {
...@@ -203,7 +203,7 @@ void TransformFeedbackVk::initDescriptorSet(ContextVk *contextVk, ...@@ -203,7 +203,7 @@ void TransformFeedbackVk::initDescriptorSet(ContextVk *contextVk,
bufferInfo.range = VK_WHOLE_SIZE; bufferInfo.range = VK_WHOLE_SIZE;
} }
writeDescriptorSet(contextVk, xfbBufferCount, descriptorBufferInfo.data(), descSet); writeDescriptorSet(contextVk, xfbBufferCount, descriptorBufferInfo, descSet);
} }
void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk, void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk,
...@@ -221,7 +221,7 @@ void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk, ...@@ -221,7 +221,7 @@ void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk,
ASSERT(programState.getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS || ASSERT(programState.getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS ||
xfbBufferCount == 1); xfbBufferCount == 1);
gl::TransformFeedbackBuffersArray<VkDescriptorBufferInfo> descriptorBufferInfo; VkDescriptorBufferInfo *descriptorBufferInfo = &contextVk->allocBufferInfos(xfbBufferCount);
// Update buffer descriptor binding info for output buffers // Update buffer descriptor binding info for output buffers
for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex) for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
...@@ -235,7 +235,7 @@ void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk, ...@@ -235,7 +235,7 @@ void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk,
ASSERT(bufferInfo.range != 0); ASSERT(bufferInfo.range != 0);
} }
writeDescriptorSet(contextVk, xfbBufferCount, descriptorBufferInfo.data(), descSet); writeDescriptorSet(contextVk, xfbBufferCount, descriptorBufferInfo, descSet);
} }
void TransformFeedbackVk::getBufferOffsets(ContextVk *contextVk, void TransformFeedbackVk::getBufferOffsets(ContextVk *contextVk,
...@@ -281,25 +281,22 @@ void TransformFeedbackVk::writeDescriptorSet(ContextVk *contextVk, ...@@ -281,25 +281,22 @@ void TransformFeedbackVk::writeDescriptorSet(ContextVk *contextVk,
VkDescriptorBufferInfo *pBufferInfo, VkDescriptorBufferInfo *pBufferInfo,
VkDescriptorSet descSet) const VkDescriptorSet descSet) const
{ {
VkDevice device = contextVk->getDevice();
ProgramExecutableVk *executableVk = contextVk->getExecutable(); ProgramExecutableVk *executableVk = contextVk->getExecutable();
ShaderMapInterfaceVariableInfoMap variableInfoMap = ShaderMapInterfaceVariableInfoMap variableInfoMap =
executableVk->getShaderInterfaceVariableInfoMap(); executableVk->getShaderInterfaceVariableInfoMap();
const std::string bufferName = GetXfbBufferName(0); const std::string bufferName = GetXfbBufferName(0);
ShaderInterfaceVariableInfo &info = variableInfoMap[gl::ShaderType::Vertex][bufferName]; ShaderInterfaceVariableInfo &info = variableInfoMap[gl::ShaderType::Vertex][bufferName];
VkWriteDescriptorSet writeDescriptorInfo = {}; VkWriteDescriptorSet &writeDescriptorInfo = contextVk->allocWriteInfo();
writeDescriptorInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptorInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorInfo.dstSet = descSet; writeDescriptorInfo.dstSet = descSet;
writeDescriptorInfo.dstBinding = info.binding; writeDescriptorInfo.dstBinding = info.binding;
writeDescriptorInfo.dstArrayElement = 0; writeDescriptorInfo.dstArrayElement = 0;
writeDescriptorInfo.descriptorCount = static_cast<uint32_t>(xfbBufferCount); writeDescriptorInfo.descriptorCount = static_cast<uint32_t>(xfbBufferCount);
writeDescriptorInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; writeDescriptorInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
writeDescriptorInfo.pImageInfo = nullptr; writeDescriptorInfo.pImageInfo = nullptr;
writeDescriptorInfo.pBufferInfo = pBufferInfo; writeDescriptorInfo.pBufferInfo = pBufferInfo;
writeDescriptorInfo.pTexelBufferView = nullptr; writeDescriptorInfo.pTexelBufferView = nullptr;
vkUpdateDescriptorSets(device, 1, &writeDescriptorInfo, 0, nullptr);
} }
} // namespace rx } // namespace rx
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment