Commit 266a9e8d by Jamie Madill Committed by Commit Bot

Vulkan: Move descriptor pools into ProgramVk.

Previously ContextVk owned the descriptor pools. We were trying to maximize descriptor reuse to conserve memory. However the default uniforms would have no possible sharing. And because uniform buffers are usually unique to a program it's likely there would be less reuse. Image descriptors could be shared. But with the advent of a descriptor cache in the Program it becomes difficult to manage the cache through descriptor pool recycling. Moving the pools into the Program simplifies the cache management. We could look at adding back more reuse in the future. Also shifts driver uniforms back into the end of the descriptor sets to make indexing into the Program's descriptor pools simpler. Bug: angleproject:3117 Change-Id: I52bb49cf322d944ad7cf08791efdf24b7fe573ce Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1644775 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent ef52c367
......@@ -193,11 +193,7 @@ void ContextVk::onDestroy(const gl::Context *context)
mIncompleteTextures.onDestroy(context);
mDriverUniformsBuffer.destroy(device);
mDriverUniformsDescriptorPoolBinding.reset();
for (vk::DynamicDescriptorPool &descriptorPool : mDynamicDescriptorPools)
{
descriptorPool.destroy(device);
}
mDriverUniformsDescriptorPool.destroy(device);
for (vk::DynamicBuffer &defaultBuffer : mDefaultAttribBuffers)
{
......@@ -240,20 +236,9 @@ angle::Result ContextVk::getIncompleteTexture(const gl::Context *context,
angle::Result ContextVk::initialize()
{
TRACE_EVENT0("gpu.angle", "ContextVk::initialize");
// Note that this may reserve more sets than strictly necessary for a particular layout.
VkDescriptorPoolSize uniformSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
GetUniformBufferDescriptorCount()};
VkDescriptorPoolSize uniformBlockSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
mRenderer->getMaxUniformBlocks()};
VkDescriptorPoolSize textureSetSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
mRenderer->getMaxActiveTextures()};
VkDescriptorPoolSize driverSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1};
ANGLE_TRY(mDynamicDescriptorPools[kUniformsDescriptorSetIndex].init(this, &uniformSetSize, 1));
ANGLE_TRY(mDynamicDescriptorPools[kUniformBlockDescriptorSetIndex].init(
this, &uniformBlockSetSize, 1));
ANGLE_TRY(mDynamicDescriptorPools[kTextureDescriptorSetIndex].init(this, &textureSetSize, 1));
ANGLE_TRY(
mDynamicDescriptorPools[kDriverUniformsDescriptorSetIndex].init(this, &driverSetSize, 1));
VkDescriptorPoolSize driverSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1};
ANGLE_TRY(mDriverUniformsDescriptorPool.init(this, &driverSetSize, 1));
ANGLE_TRY(mQueryPools[gl::QueryType::AnySamples].init(this, VK_QUERY_TYPE_OCCLUSION,
vk::kDefaultOcclusionQueryPoolSize));
......@@ -268,6 +253,10 @@ angle::Result ContextVk::initialize()
mRenderer->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment);
mDriverUniformsBuffer.init(minAlignment, mRenderer);
// Get the descriptor set layout.
vk::DescriptorSetLayoutDesc desc = getDriverUniformsDescriptorSetDesc();
ANGLE_TRY(mRenderer->getDescriptorSetLayout(this, desc, &mDriverUniformsSetLayout));
mGraphicsPipelineDesc.reset(new vk::GraphicsPipelineDesc());
mGraphicsPipelineDesc->initDefaults();
......@@ -1876,11 +1865,6 @@ angle::Result ContextVk::memoryBarrierByRegion(const gl::Context *context, GLbit
return angle::Result::Stop;
}
vk::DynamicDescriptorPool *ContextVk::getDynamicDescriptorPool(uint32_t descriptorSetIndex)
{
return &mDynamicDescriptorPools[descriptorSetIndex];
}
vk::DynamicQueryPool *ContextVk::getQueryPool(gl::QueryType queryType)
{
ASSERT(queryType == gl::QueryType::AnySamples ||
......@@ -1940,19 +1924,10 @@ angle::Result ContextVk::handleDirtyDriverUniforms(const gl::Context *context,
ANGLE_TRY(mDriverUniformsBuffer.flush(this));
// Get the descriptor set layout.
if (!mDriverUniformsSetLayout.valid())
{
vk::DescriptorSetLayoutDesc desc;
desc.update(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL_GRAPHICS);
ANGLE_TRY(getRenderer()->getDescriptorSetLayout(this, desc, &mDriverUniformsSetLayout));
}
// Allocate a new descriptor set.
ANGLE_TRY(mDynamicDescriptorPools[kDriverUniformsDescriptorSetIndex].allocateSets(
this, mDriverUniformsSetLayout.get().ptr(), 1, &mDriverUniformsDescriptorPoolBinding,
&mDriverUniformsDescriptorSet));
ANGLE_TRY(mDriverUniformsDescriptorPool.allocateSets(this, mDriverUniformsSetLayout.get().ptr(),
1, &mDriverUniformsDescriptorPoolBinding,
&mDriverUniformsDescriptorSet));
// Update the driver uniform descriptor set.
VkDescriptorBufferInfo bufferInfo = {};
......@@ -2398,4 +2373,10 @@ angle::Result ContextVk::generateSurfaceSemaphores(SignalSemaphoreVector *signal
return angle::Result::Continue;
}
vk::DescriptorSetLayoutDesc ContextVk::getDriverUniformsDescriptorSetDesc() const
{
vk::DescriptorSetLayoutDesc desc;
desc.update(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL_GRAPHICS);
return desc;
}
} // namespace rx
......@@ -214,7 +214,6 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
void invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask);
void onFramebufferChange(const vk::RenderPassDesc &renderPassDesc);
vk::DynamicDescriptorPool *getDynamicDescriptorPool(uint32_t descriptorSetIndex);
vk::DynamicQueryPool *getQueryPool(gl::QueryType queryType);
const VkClearValue &getClearColorValue() const;
......@@ -300,6 +299,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
RenderPassCache &getRenderPassCache() { return mRenderPassCache; }
vk::DescriptorSetLayoutDesc getDriverUniformsDescriptorSetDesc() const;
private:
// Dirty bits.
enum DirtyBitType : size_t
......@@ -406,12 +407,11 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
std::unique_ptr<vk::GraphicsPipelineDesc> mGraphicsPipelineDesc;
vk::GraphicsPipelineTransitionBits mGraphicsPipelineTransition;
// The descriptor pools are externally sychronized, so cannot be accessed from different
// These pools are externally sychronized, so cannot be accessed from different
// threads simultaneously. Hence, we keep them in the ContextVk instead of the RendererVk.
// Note that this implementation would need to change in shared resource scenarios. Likely
// we'd instead share a single set of dynamic descriptor pools between the share groups.
// Same with query pools.
vk::DescriptorSetLayoutArray<vk::DynamicDescriptorPool> mDynamicDescriptorPools;
// we'd instead share a single set of pools between the share groups.
vk::DynamicDescriptorPool mDriverUniformsDescriptorPool;
angle::PackedEnumMap<gl::QueryType, vk::DynamicQueryPool> mQueryPools;
// Dirty bits.
......
......@@ -256,6 +256,11 @@ void ProgramVk::reset(ContextVk *contextVk)
{
binding.reset();
}
for (vk::DynamicDescriptorPool &descriptorPool : mDynamicDescriptorPools)
{
descriptorPool.release(contextVk);
}
}
std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context,
......@@ -350,9 +355,8 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext,
ANGLE_TRY(renderer->getDescriptorSetLayout(contextVk, texturesSetDesc,
&mDescriptorSetLayouts[kTextureDescriptorSetIndex]));
vk::DescriptorSetLayoutDesc driverUniformsSetDesc;
driverUniformsSetDesc.update(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
VK_SHADER_STAGE_ALL_GRAPHICS);
vk::DescriptorSetLayoutDesc driverUniformsSetDesc =
contextVk->getDriverUniformsDescriptorSetDesc();
ANGLE_TRY(renderer->getDescriptorSetLayout(
contextVk, driverUniformsSetDesc,
&mDescriptorSetLayouts[kDriverUniformsDescriptorSetIndex]));
......@@ -368,6 +372,21 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext,
ANGLE_TRY(renderer->getPipelineLayout(contextVk, pipelineLayoutDesc, mDescriptorSetLayouts,
&mPipelineLayout));
// Note that this may reserve more sets than strictly necessary for a particular layout.
// TODO(jmadill): Optimize descriptor counts. http://anglebug.com/3117
VkDescriptorPoolSize uniformSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
GetUniformBufferDescriptorCount()};
VkDescriptorPoolSize uniformBlockSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
renderer->getMaxUniformBlocks()};
VkDescriptorPoolSize textureSetSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
renderer->getMaxActiveTextures()};
ANGLE_TRY(
mDynamicDescriptorPools[kUniformsDescriptorSetIndex].init(contextVk, &uniformSetSize, 1));
ANGLE_TRY(mDynamicDescriptorPools[kUniformBlockDescriptorSetIndex].init(
contextVk, &uniformBlockSetSize, 1));
ANGLE_TRY(
mDynamicDescriptorPools[kTextureDescriptorSetIndex].init(contextVk, &textureSetSize, 1));
return angle::Result::Continue;
}
......@@ -760,9 +779,7 @@ void ProgramVk::setPathFragmentInputGen(const std::string &inputName,
angle::Result ProgramVk::allocateDescriptorSet(ContextVk *contextVk, uint32_t descriptorSetIndex)
{
// Write out to a new a descriptor set.
vk::DynamicDescriptorPool *dynamicDescriptorPool =
contextVk->getDynamicDescriptorPool(descriptorSetIndex);
vk::DynamicDescriptorPool &dynamicDescriptorPool = mDynamicDescriptorPools[descriptorSetIndex];
uint32_t potentialNewCount = descriptorSetIndex + 1;
if (potentialNewCount > mDescriptorSets.size())
......@@ -772,9 +789,9 @@ angle::Result ProgramVk::allocateDescriptorSet(ContextVk *contextVk, uint32_t de
const vk::DescriptorSetLayout &descriptorSetLayout =
mDescriptorSetLayouts[descriptorSetIndex].get();
ANGLE_TRY(dynamicDescriptorPool->allocateSets(contextVk, descriptorSetLayout.ptr(), 1,
&mDescriptorPoolBindings[descriptorSetIndex],
&mDescriptorSets[descriptorSetIndex]));
ANGLE_TRY(dynamicDescriptorPool.allocateSets(contextVk, descriptorSetLayout.ptr(), 1,
&mDescriptorPoolBindings[descriptorSetIndex],
&mDescriptorSets[descriptorSetIndex]));
mEmptyDescriptorSets[descriptorSetIndex] = VK_NULL_HANDLE;
return angle::Result::Continue;
......@@ -1082,12 +1099,10 @@ angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk,
// later sets to misbehave.
if (mEmptyDescriptorSets[descriptorSetIndex] == VK_NULL_HANDLE)
{
vk::DynamicDescriptorPool *dynamicDescriptorPool =
contextVk->getDynamicDescriptorPool(descriptorSetIndex);
const vk::DescriptorSetLayout &descriptorSetLayout =
mDescriptorSetLayouts[descriptorSetIndex].get();
ANGLE_TRY(dynamicDescriptorPool->allocateSets(
ANGLE_TRY(mDynamicDescriptorPools[descriptorSetIndex].allocateSets(
contextVk, descriptorSetLayout.ptr(), 1,
&mDescriptorPoolBindings[descriptorSetIndex],
&mEmptyDescriptorSets[descriptorSetIndex]));
......
......@@ -139,6 +139,12 @@ class ProgramVk : public ProgramImpl
descPtrOut, pipelineOut);
}
// Used in testing only.
vk::DynamicDescriptorPool *getDynamicDescriptorPool(uint32_t poolIndex)
{
return &mDynamicDescriptorPools[poolIndex];
}
private:
template <int cols, int rows>
void setUniformMatrixfv(GLint location,
......@@ -257,6 +263,11 @@ class ProgramVk : public ProgramImpl
// We keep the translated linked shader sources to use with shader draw call patching.
std::string mVertexSource;
std::string mFragmentSource;
// Store descriptor pools here. We store the descriptors in the Program to facilitate descriptor
// cache management. It can also allow fewer descriptors for shaders which use fewer
// textures/buffers.
vk::DescriptorSetLayoutArray<vk::DynamicDescriptorPool> mDynamicDescriptorPools;
};
} // namespace rx
......
......@@ -867,14 +867,14 @@ class PipelineLayoutCache final : angle::NonCopyable
// - Set 2 contains all textures.
// - Set 3 contains all uniform blocks.
// ANGLE driver uniforms set index (binding is always 0):
constexpr uint32_t kDriverUniformsDescriptorSetIndex = 0;
// Uniforms set index:
constexpr uint32_t kUniformsDescriptorSetIndex = 1;
constexpr uint32_t kUniformsDescriptorSetIndex = 0;
// Textures set index:
constexpr uint32_t kTextureDescriptorSetIndex = 2;
constexpr uint32_t kTextureDescriptorSetIndex = 1;
// Uniform blocks set index:
constexpr uint32_t kUniformBlockDescriptorSetIndex = 3;
constexpr uint32_t kUniformBlockDescriptorSetIndex = 2;
// ANGLE driver uniforms set index (binding is always 3):
constexpr uint32_t kDriverUniformsDescriptorSetIndex = 3;
// Only 1 driver uniform binding is used.
constexpr uint32_t kReservedDriverUniformBindingCount = 1;
......
......@@ -512,6 +512,11 @@ void DescriptorPoolHelper::destroy(VkDevice device)
mDescriptorPool.destroy(device);
}
void DescriptorPoolHelper::release(ContextVk *contextVk)
{
contextVk->releaseObject(contextVk->getCurrentQueueSerial(), &mDescriptorPool);
}
angle::Result DescriptorPoolHelper::allocateSets(ContextVk *context,
const VkDescriptorSetLayout *descriptorSetLayout,
uint32_t descriptorSetCount,
......@@ -568,6 +573,18 @@ void DynamicDescriptorPool::destroy(VkDevice device)
mDescriptorPools.clear();
}
void DynamicDescriptorPool::release(ContextVk *contextVk)
{
for (RefCountedDescriptorPoolHelper *pool : mDescriptorPools)
{
ASSERT(!pool->isReferenced());
pool->get().release(contextVk);
delete pool;
}
mDescriptorPools.clear();
}
angle::Result DynamicDescriptorPool::allocateSets(ContextVk *context,
const VkDescriptorSetLayout *descriptorSetLayout,
uint32_t descriptorSetCount,
......
......@@ -119,6 +119,7 @@ class DescriptorPoolHelper
const std::vector<VkDescriptorPoolSize> &poolSizes,
uint32_t maxSets);
void destroy(VkDevice device);
void release(ContextVk *contextVk);
angle::Result allocateSets(ContextVk *context,
const VkDescriptorSetLayout *descriptorSetLayout,
......@@ -151,6 +152,7 @@ class DynamicDescriptorPool final : angle::NonCopyable
const VkDescriptorPoolSize *setSizes,
uint32_t setSizeCount);
void destroy(VkDevice device);
void release(ContextVk *contextVk);
// We use the descriptor type to help count the number of free sets.
// By convention, sets are indexed according to the constants in vk_cache_utils.h.
......
......@@ -731,3 +731,6 @@
3193 ANDROID VULKAN : dEQP-GLES3.functional.vertex_arrays.single_attribute.output_types.unsigned_byte.components* = FAIL
3193 ANDROID VULKAN : dEQP-GLES3.functional.vertex_arrays.single_attribute.output_types.short.components* = FAIL
3193 ANDROID VULKAN : dEQP-GLES3.functional.vertex_arrays.single_attribute.output_types.unsigned_short.components* = FAIL
// Fixed in later driver versions.
2727 VULKAN ANDROID : dEQP-GLES3.functional.shaders.builtin_variable.pointcoord = FAIL
......@@ -46,20 +46,21 @@ class VulkanUniformUpdatesTest : public ANGLETest
static constexpr uint32_t kMaxSetsForTesting = 32;
void limitMaxSets()
void limitMaxSets(GLuint program)
{
rx::ContextVk *contextVk = hackANGLE();
rx::ProgramVk *programVk = hackProgram(program);
// Force a small limit on the max sets per pool to more easily trigger a new allocation.
rx::vk::DynamicDescriptorPool *uniformPool =
contextVk->getDynamicDescriptorPool(rx::kUniformsDescriptorSetIndex);
programVk->getDynamicDescriptorPool(rx::kUniformsDescriptorSetIndex);
uniformPool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting);
VkDescriptorPoolSize uniformSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
rx::GetUniformBufferDescriptorCount()};
(void)uniformPool->init(contextVk, &uniformSetSize, 1);
rx::vk::DynamicDescriptorPool *texturePool =
contextVk->getDynamicDescriptorPool(rx::kTextureDescriptorSetIndex);
programVk->getDynamicDescriptorPool(rx::kTextureDescriptorSetIndex);
texturePool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting);
VkDescriptorPoolSize textureSetSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
contextVk->getRenderer()->getMaxActiveTextures()};
......@@ -73,8 +74,6 @@ TEST_P(VulkanUniformUpdatesTest, UpdateUntilNewBufferIsAllocated)
{
ASSERT_TRUE(IsVulkan());
limitMaxSets();
constexpr char kPositionUniformVertexShader[] = R"(attribute vec2 position;
uniform vec2 uniPosModifier;
void main()
......@@ -92,6 +91,8 @@ void main()
ANGLE_GL_PROGRAM(program, kPositionUniformVertexShader, kColorUniformFragmentShader);
glUseProgram(program);
limitMaxSets(program);
rx::ProgramVk *programVk = hackProgram(program);
// Set a really small min size so that uniform updates often allocates a new buffer.
......@@ -128,14 +129,14 @@ TEST_P(VulkanUniformUpdatesTest, DescriptorPoolUpdates)
{
ASSERT_TRUE(IsVulkan());
// Force a small limit on the max sets per pool to more easily trigger a new allocation.
limitMaxSets();
// Initialize texture program.
GLuint program = get2DTexturedQuadProgram();
ASSERT_NE(0u, program);
glUseProgram(program);
// Force a small limit on the max sets per pool to more easily trigger a new allocation.
limitMaxSets(program);
GLint texLoc = glGetUniformLocation(program, "tex");
ASSERT_NE(-1, texLoc);
......@@ -163,8 +164,6 @@ TEST_P(VulkanUniformUpdatesTest, DescriptorPoolUniformAndTextureUpdates)
{
ASSERT_TRUE(IsVulkan());
limitMaxSets();
// Initialize texture program.
constexpr char kVS[] = R"(attribute vec2 position;
varying mediump vec2 texCoord;
......@@ -185,6 +184,8 @@ void main()
ANGLE_GL_PROGRAM(program, kVS, kFS);
glUseProgram(program);
limitMaxSets(program);
// Get uniform locations.
GLint texLoc = glGetUniformLocation(program, "tex");
ASSERT_NE(-1, texLoc);
......@@ -239,9 +240,6 @@ TEST_P(VulkanUniformUpdatesTest, DescriptorPoolUniformAndTextureUpdatesTwoShader
{
ASSERT_TRUE(IsVulkan());
// Force a small limit on the max sets per pool to more easily trigger a new allocation.
limitMaxSets();
// Initialize program.
constexpr char kVS[] = R"(attribute vec2 position;
varying mediump vec2 texCoord;
......@@ -262,6 +260,10 @@ void main()
ANGLE_GL_PROGRAM(program2, kVS, kFS);
glUseProgram(program1);
// Force a small limit on the max sets per pool to more easily trigger a new allocation.
limitMaxSets(program1);
limitMaxSets(program2);
rx::ProgramVk *program1Vk = hackProgram(program1);
rx::ProgramVk *program2Vk = hackProgram(program2);
......
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