Commit 9b168d02 by Jamie Madill Committed by Commit Bot

Vulkan: Store Pipeline/DS Layouts in ProgramVk.

We can keep a shared reference to the Pipeline and Descriptor Set layouts in the Program. This ensures they are not in use when they are deleted. Note that they are allowed to be deleted as long as no command buffers are currently recording with them. If the Program is deleted then there should be no further commands using these layouts. Bug: angleproject:2462 Change-Id: I75161b3ce1ee8eae33dd6becee79b4262b844cdd Reviewed-on: https://chromium-review.googlesource.com/1089807 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org>
parent c7918ceb
......@@ -125,11 +125,9 @@ gl::Error ContextVk::initPipeline()
// Ensure that the RenderPass description is updated.
mPipelineDesc->updateRenderPassDesc(framebufferVk->getRenderPassDesc());
const vk::PipelineLayout &pipelineLayout = mRenderer->getGraphicsPipelineLayout();
// TODO(jmadill): Validate with ASSERT against physical device limits/caps?
ANGLE_TRY(mRenderer->getAppPipeline(programVk, *mPipelineDesc, activeAttribLocationsMask,
pipelineLayout, &mCurrentPipeline));
&mCurrentPipeline));
return gl::NoError();
}
......@@ -216,7 +214,7 @@ gl::Error ContextVk::setupDraw(const gl::Context *context,
if (!usedRange.empty())
{
ASSERT(!descriptorSets.empty());
const vk::PipelineLayout &pipelineLayout = mRenderer->getGraphicsPipelineLayout();
const vk::PipelineLayout &pipelineLayout = programVk->getPipelineLayout();
(*commandBufferOut)
->bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, usedRange.low(),
......
......@@ -172,6 +172,12 @@ vk::Error ProgramVk::reset(ContextVk *contextVk)
VkDevice device = contextVk->getDevice();
for (auto &descriptorSetLayout : mDescriptorSetLayouts)
{
descriptorSetLayout.reset();
}
mPipelineLayout.reset();
for (auto &uniformBlock : mDefaultUniformBlocks)
{
uniformBlock.storage.destroy(device);
......@@ -266,10 +272,40 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext,
if (!mState.getSamplerUniformRange().empty())
{
// Ensure the descriptor set range includes the textures at position 1.
mUsedDescriptorSetRange.extend(1);
mUsedDescriptorSetRange.extend(kTextureDescriptorSetIndex);
mDirtyTextures = true;
}
// Store a reference to the pipeline and descriptor set layouts. This will create them if they
// don't already exist in the cache.
vk::DescriptorSetLayoutDesc uniformsSetDesc;
uniformsSetDesc.update(kVertexUniformsBindingIndex, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
1);
uniformsSetDesc.update(kFragmentUniformsBindingIndex, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
1);
ANGLE_TRY(renderer->getDescriptorSetLayout(
uniformsSetDesc, &mDescriptorSetLayouts[kUniformsDescriptorSetIndex]));
const uint32_t maxTextures = renderer->getMaxActiveTextures();
vk::DescriptorSetLayoutDesc texturesSetDesc;
for (uint32_t textureIndex = 0; textureIndex < maxTextures; ++textureIndex)
{
// TODO(jmadll): Sampler arrays. http://anglebug.com/2462
texturesSetDesc.update(textureIndex, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1);
}
ANGLE_TRY(renderer->getDescriptorSetLayout(texturesSetDesc,
&mDescriptorSetLayouts[kTextureDescriptorSetIndex]));
vk::PipelineLayoutDesc pipelineLayoutDesc;
pipelineLayoutDesc.updateDescriptorSetLayout(kUniformsDescriptorSetIndex, uniformsSetDesc);
pipelineLayoutDesc.updateDescriptorSetLayout(kTextureDescriptorSetIndex, texturesSetDesc);
ANGLE_TRY(
renderer->getPipelineLayout(pipelineLayoutDesc, mDescriptorSetLayouts, &mPipelineLayout));
return true;
}
......@@ -701,8 +737,6 @@ Serial ProgramVk::getFragmentModuleSerial() const
vk::Error ProgramVk::allocateDescriptorSet(ContextVk *contextVk, uint32_t descriptorSetIndex)
{
RendererVk *renderer = contextVk->getRenderer();
// Write out to a new a descriptor set.
vk::DynamicDescriptorPool *dynamicDescriptorPool = contextVk->getDynamicDescriptorPool();
......@@ -713,8 +747,7 @@ vk::Error ProgramVk::allocateDescriptorSet(ContextVk *contextVk, uint32_t descri
}
const vk::DescriptorSetLayout &descriptorSetLayout =
renderer->getGraphicsDescriptorSetLayout(descriptorSetIndex);
mDescriptorSetLayouts[descriptorSetIndex].get();
ANGLE_TRY(dynamicDescriptorPool->allocateDescriptorSets(contextVk, descriptorSetLayout.ptr(), 1,
&mDescriptorSets[descriptorSetIndex]));
return vk::NoError();
......@@ -925,6 +958,11 @@ void ProgramVk::invalidateTextures()
mDirtyTextures = true;
}
const vk::PipelineLayout &ProgramVk::getPipelineLayout() const
{
return mPipelineLayout.get();
}
void ProgramVk::setDefaultUniformBlocksMinSizeForTesting(size_t minSize)
{
for (DefaultUniformBlock &block : mDefaultUniformBlocks)
......
......@@ -121,6 +121,8 @@ class ProgramVk : public ProgramImpl
gl::Error updateTexturesDescriptorSet(const gl::Context *context);
void invalidateTextures();
const vk::PipelineLayout &getPipelineLayout() const;
// For testing only.
void setDefaultUniformBlocksMinSizeForTesting(size_t minSize);
......@@ -179,6 +181,11 @@ class ProgramVk : public ProgramImpl
template <typename T>
using ShaderTextureArray = std::array<T, gl::IMPLEMENTATION_MAX_SHADER_TEXTURES>;
// We keep a reference to the pipeline and descriptor set layouts. This ensures they don't get
// deleted while this program is in use.
vk::BindingPointer<vk::PipelineLayout> mPipelineLayout;
vk::DescriptorSetLayoutPointerArray mDescriptorSetLayouts;
};
} // namespace rx
......
......@@ -208,12 +208,6 @@ RendererVk::~RendererVk()
}
}
for (auto &descriptorSetLayout : mGraphicsDescriptorSetLayouts)
{
descriptorSetLayout.reset();
}
mGraphicsPipelineLayout.reset();
mPipelineLayoutCache.destroy(mDevice);
mDescriptorSetLayoutCache.destroy(mDevice);
......@@ -449,9 +443,6 @@ vk::Error RendererVk::initialize(const egl::AttributeMap &attribs, const char *w
mFormatTable.initialize(mPhysicalDevice, &mNativeTextureCaps,
&mNativeCaps.compressedTextureFormats);
// Initialize the pipeline layout for GL programs.
ANGLE_TRY(initGraphicsPipelineLayout());
return vk::NoError();
}
......@@ -843,51 +834,6 @@ vk::Error RendererVk::flush(const gl::Context *context,
return vk::NoError();
}
const vk::PipelineLayout &RendererVk::getGraphicsPipelineLayout() const
{
return mGraphicsPipelineLayout.get();
}
const vk::DescriptorSetLayout &RendererVk::getGraphicsDescriptorSetLayout(uint32_t setIndex) const
{
return mGraphicsDescriptorSetLayouts[setIndex].get();
}
vk::Error RendererVk::initGraphicsPipelineLayout()
{
ASSERT(!mGraphicsPipelineLayout.valid());
// Create two descriptor set layouts: one for default uniform info, and one for textures.
vk::DescriptorSetLayoutDesc uniformsSetDesc;
uniformsSetDesc.update(kVertexUniformsBindingIndex, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
1);
uniformsSetDesc.update(kFragmentUniformsBindingIndex, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
1);
ANGLE_TRY(mDescriptorSetLayoutCache.getDescriptorSetLayout(mDevice, uniformsSetDesc,
&mGraphicsDescriptorSetLayouts[0]));
const uint32_t maxTextures = getMaxActiveTextures();
vk::DescriptorSetLayoutDesc texturesSetDesc;
for (uint32_t textureIndex = 0; textureIndex < maxTextures; ++textureIndex)
{
// TODO(jmadll): Sampler arrays. http://anglebug.com/2462
texturesSetDesc.update(textureIndex, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1);
}
ANGLE_TRY(mDescriptorSetLayoutCache.getDescriptorSetLayout(mDevice, texturesSetDesc,
&mGraphicsDescriptorSetLayouts[1]));
vk::PipelineLayoutDesc pipelineLayoutDesc;
pipelineLayoutDesc.updateDescriptorSetLayout(kUniformsDescriptorSetIndex, uniformsSetDesc);
pipelineLayoutDesc.updateDescriptorSetLayout(kTextureDescriptorSetIndex, texturesSetDesc);
ANGLE_TRY(mPipelineLayoutCache.getPipelineLayout(
mDevice, pipelineLayoutDesc, mGraphicsDescriptorSetLayouts, &mGraphicsPipelineLayout));
return vk::NoError();
}
vk::Error RendererVk::getInternalPushConstantPipelineLayout(
const vk::PipelineLayout **pipelineLayoutOut)
{
......@@ -924,7 +870,6 @@ Serial RendererVk::issueShaderSerial()
vk::Error RendererVk::getAppPipeline(const ProgramVk *programVk,
const vk::PipelineDesc &desc,
const gl::AttributesMask &activeAttribLocationsMask,
const vk::PipelineLayout &pipelineLayout,
vk::PipelineAndSerial **pipelineOut)
{
ASSERT(programVk->getVertexModuleSerial() ==
......@@ -936,6 +881,8 @@ vk::Error RendererVk::getAppPipeline(const ProgramVk *programVk,
vk::RenderPass *compatibleRenderPass = nullptr;
ANGLE_TRY(getCompatibleRenderPass(desc.getRenderPassDesc(), &compatibleRenderPass));
const vk::PipelineLayout &pipelineLayout = programVk->getPipelineLayout();
return mPipelineCache.getPipeline(mDevice, *compatibleRenderPass, pipelineLayout,
activeAttribLocationsMask, programVk->getLinkedVertexModule(),
programVk->getLinkedFragmentModule(), desc, pipelineOut);
......@@ -962,6 +909,22 @@ vk::Error RendererVk::getInternalPipeline(const vk::ShaderAndSerial &vertexShade
fragmentShader.get(), pipelineDesc, pipelineOut);
}
vk::Error RendererVk::getDescriptorSetLayout(
const vk::DescriptorSetLayoutDesc &desc,
vk::BindingPointer<vk::DescriptorSetLayout> *descriptorSetLayoutOut)
{
return mDescriptorSetLayoutCache.getDescriptorSetLayout(mDevice, desc, descriptorSetLayoutOut);
}
vk::Error RendererVk::getPipelineLayout(
const vk::PipelineLayoutDesc &desc,
const vk::DescriptorSetLayoutPointerArray &descriptorSetLayouts,
vk::BindingPointer<vk::PipelineLayout> *pipelineLayoutOut)
{
return mPipelineLayoutCache.getPipelineLayout(mDevice, desc, descriptorSetLayouts,
pipelineLayoutOut);
}
vk::ShaderLibrary *RendererVk::getShaderLibrary()
{
return &mShaderLibrary;
......
......@@ -108,7 +108,6 @@ class RendererVk : angle::NonCopyable
vk::Error getAppPipeline(const ProgramVk *programVk,
const vk::PipelineDesc &desc,
const gl::AttributesMask &activeAttribLocationsMask,
const vk::PipelineLayout &pipelineLayout,
vk::PipelineAndSerial **pipelineOut);
// For getting a vk::Pipeline for an internal draw call. Use an explicit RenderPass.
......@@ -119,14 +118,20 @@ class RendererVk : angle::NonCopyable
const gl::AttributesMask &activeAttribLocationsMask,
vk::PipelineAndSerial **pipelineOut);
// Queries the descriptor set layout cache. Creates the layout if not present.
vk::Error getDescriptorSetLayout(
const vk::DescriptorSetLayoutDesc &desc,
vk::BindingPointer<vk::DescriptorSetLayout> *descriptorSetLayoutOut);
// Queries the pipeline layout cache. Creates the layout if not present.
vk::Error getPipelineLayout(const vk::PipelineLayoutDesc &desc,
const vk::DescriptorSetLayoutPointerArray &descriptorSetLayouts,
vk::BindingPointer<vk::PipelineLayout> *pipelineLayoutOut);
// This should only be called from ResourceVk.
// TODO(jmadill): Keep in ContextVk to enable threaded rendering.
vk::CommandGraph *getCommandGraph();
// TODO(jmadill): Use PipelineLayout cache. http://anglebug.com/2462
const vk::PipelineLayout &getGraphicsPipelineLayout() const;
const vk::DescriptorSetLayout &getGraphicsDescriptorSetLayout(uint32_t setIndex) const;
// Used in internal shaders.
// TODO(jmadill): Use PipelineLayout cache. http://anglebug.com/2462
vk::Error getInternalPushConstantPipelineLayout(const vk::PipelineLayout **pipelineLayoutOut);
......@@ -143,7 +148,6 @@ class RendererVk : angle::NonCopyable
vk::Error checkInFlightCommands();
void freeAllInFlightResources();
vk::Error flushCommandGraph(const gl::Context *context, vk::CommandBuffer *commandBatch);
vk::Error initGraphicsPipelineLayout();
mutable bool mCapsInitialized;
mutable gl::Caps mNativeCaps;
......@@ -196,10 +200,6 @@ class RendererVk : angle::NonCopyable
// DescriptorSetLayouts are also managed in a cache.
DescriptorSetLayoutCache mDescriptorSetLayoutCache;
// TODO(jmadill): Only use the pipeline layout cache. http://anglebug.com/2462
vk::BindingPointer<vk::PipelineLayout> mGraphicsPipelineLayout;
vk::DescriptorSetLayoutPointerArray mGraphicsDescriptorSetLayouts;
// Used for internal shaders.
// TODO(jmadill): Use PipelineLayout cache. http://anglebug.com/2462
vk::PipelineLayout mInternalPushConstantPipelineLayout;
......
......@@ -83,9 +83,13 @@ class DynamicBuffer : angle::NonCopyable
std::vector<BufferAndMemory> mRetainedBuffers;
};
// Uses DescriptorPool to allocate descriptor sets as needed. If the descriptor pool
// is full, we simply allocate a new pool to keep allocating descriptor sets as needed and
// leave the renderer take care of the life time of the pools that become unused.
// Uses DescriptorPool to allocate descriptor sets as needed. If a descriptor pool becomes full, we
// allocate new pools internally as needed. RendererVk takes care of the lifetime of the discarded
// pools. Note that we used a fixed layout for descriptor pools in ANGLE. Uniform buffers must
// use set zero and combined Image Samplers must use set 1. We conservatively count each new set
// using the maximum number of descriptor sets and buffers with each allocation. Currently: 2
// (Vertex/Fragment) uniform buffers and 64 (MAX_ACTIVE_TEXTURES) image/samplers.
class DynamicDescriptorPool final : angle::NonCopyable
{
public:
......
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