vk_find_struct_const(pCreateInfo->pNext,
DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO);
- struct vn_descriptor_pool *pool =
- vk_zalloc(alloc, sizeof(*pool), VN_DEFAULT_ALIGN,
- VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+ uint32_t mutable_states_count = 0;
+ for (uint32_t i = 0; i < pCreateInfo->poolSizeCount; i++) {
+ const VkDescriptorPoolSize *pool_size = &pCreateInfo->pPoolSizes[i];
+ if (pool_size->type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE)
+ mutable_states_count++;
+ }
+ struct vn_descriptor_pool *pool;
+ struct vn_descriptor_pool_state_mutable *mutable_states;
- if (!pool)
+ VK_MULTIALLOC(ma);
+ vk_multialloc_add(&ma, &pool, __typeof__(*pool), 1);
+ vk_multialloc_add(&ma, &mutable_states, __typeof__(*mutable_states),
+ mutable_states_count);
+
+ if (!vk_multialloc_zalloc(&ma, alloc, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT))
return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
vn_object_base_init(&pool->base, VK_OBJECT_TYPE_DESCRIPTOR_POOL,
&dev->base);
pool->allocator = *alloc;
+ pool->mutable_states = mutable_states;
+
+ const VkMutableDescriptorTypeCreateInfoVALVE *mutable_descriptor_info =
+ vk_find_struct_const(pCreateInfo->pNext,
+ MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE);
/* Without VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, the set
* allocation must not fail due to a fragmented pool per spec. In this
if (iub_info)
pool->max.iub_binding_count = iub_info->maxInlineUniformBlockBindings;
+ uint32_t next_mutable_state = 0;
for (uint32_t i = 0; i < pCreateInfo->poolSizeCount; i++) {
const VkDescriptorPoolSize *pool_size = &pCreateInfo->pPoolSizes[i];
const uint32_t type_index = vn_descriptor_type_index(pool_size->type);
assert(type_index < VN_NUM_DESCRIPTOR_TYPES);
- pool->max.descriptor_counts[type_index] += pool_size->descriptorCount;
+ if (type_index == VN_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
+ struct vn_descriptor_pool_state_mutable *mutable_state = NULL;
+ BITSET_DECLARE(mutable_types, VN_NUM_DESCRIPTOR_TYPES);
+ if (!mutable_descriptor_info ||
+ i >= mutable_descriptor_info->mutableDescriptorTypeListCount) {
+ BITSET_ONES(mutable_types);
+ } else {
+ const VkMutableDescriptorTypeListVALVE *list =
+ &mutable_descriptor_info->pMutableDescriptorTypeLists[i];
+
+ for (uint32_t j = 0; j < list->descriptorTypeCount; j++) {
+ BITSET_SET(mutable_types, vn_descriptor_type_index(
+ list->pDescriptorTypes[j]));
+ }
+ }
+ for (uint32_t j = 0; j < next_mutable_state; j++) {
+ if (BITSET_EQUAL(mutable_types, pool->mutable_states[j].types)) {
+ mutable_state = &pool->mutable_states[j];
+ break;
+ }
+ }
+
+ if (!mutable_state) {
+ /* The application must ensure that partial overlap does not
+ * exist in pPoolSizes. so this entry must have a disjoint set
+ * of types.
+ */
+ mutable_state = &pool->mutable_states[next_mutable_state++];
+ BITSET_COPY(mutable_state->types, mutable_types);
+ }
+
+ mutable_state->max += pool_size->descriptorCount;
+ } else {
+ pool->max.descriptor_counts[type_index] +=
+ pool_size->descriptorCount;
+ }
assert((pCreateInfo->pPoolSizes[i].type !=
VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) ||
iub_info);
}
+ pool->mutable_states_count = next_mutable_state;
list_inithead(&pool->descriptor_sets);
VkDescriptorPool pool_handle = vn_descriptor_pool_to_handle(pool);
vk_free(alloc, pool);
}
+static struct vn_descriptor_pool_state_mutable *
+vn_find_mutable_state_for_binding(
+ const struct vn_descriptor_pool *pool,
+ const struct vn_descriptor_set_layout_binding *binding)
+{
+ for (uint32_t i = 0; i < pool->mutable_states_count; i++) {
+ struct vn_descriptor_pool_state_mutable *mutable_state =
+ &pool->mutable_states[i];
+ BITSET_DECLARE(shared_types, VN_NUM_DESCRIPTOR_TYPES);
+ BITSET_AND(shared_types, mutable_state->types,
+ binding->mutable_descriptor_types);
+
+ if (BITSET_EQUAL(shared_types, binding->mutable_descriptor_types)) {
+ /* The application must ensure that partial overlap does not
+ * exist in pPoolSizes. so there should be at most 1
+ * matching pool entry for a binding.
+ */
+ return mutable_state;
+ }
+ }
+ return NULL;
+}
+
+static void
+vn_pool_restore_mutable_states(struct vn_descriptor_pool *pool,
+ const struct vn_descriptor_set_layout *layout,
+ uint32_t max_binding_index,
+ uint32_t last_binding_descriptor_count)
+{
+ for (uint32_t i = 0; i <= max_binding_index; i++) {
+ if (layout->bindings[i].type != VK_DESCRIPTOR_TYPE_MUTABLE_VALVE)
+ continue;
+
+ const uint32_t count = i == layout->last_binding
+ ? last_binding_descriptor_count
+ : layout->bindings[i].count;
+
+ struct vn_descriptor_pool_state_mutable *mutable_state =
+ vn_find_mutable_state_for_binding(pool, &layout->bindings[i]);
+ assert(mutable_state && mutable_state->used >= count);
+ mutable_state->used -= count;
+ }
+}
+
static bool
vn_descriptor_pool_alloc_descriptors(
struct vn_descriptor_pool *pool,
++pool->used.set_count;
- for (uint32_t i = 0; i <= layout->last_binding; i++) {
- const VkDescriptorType type = layout->bindings[i].type;
- const uint32_t count = i == layout->last_binding
+ uint32_t binding_index = 0;
+
+ while (binding_index <= layout->last_binding) {
+ const VkDescriptorType type = layout->bindings[binding_index].type;
+ const uint32_t count = binding_index == layout->last_binding
? last_binding_descriptor_count
- : layout->bindings[i].count;
+ : layout->bindings[binding_index].count;
/* Allocation may fail if a call to vkAllocateDescriptorSets would cause
* the total number of inline uniform block bindings allocated from the
* used to create the descriptor pool.
*/
if (type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) {
- if (++pool->used.iub_binding_count > pool->max.iub_binding_count) {
- /* restore pool state before this allocation */
- pool->used = recovery;
- return false;
- }
+ if (++pool->used.iub_binding_count > pool->max.iub_binding_count)
+ goto fail;
}
- const uint32_t type_index = vn_descriptor_type_index(type);
- pool->used.descriptor_counts[type_index] += count;
-
- if (pool->used.descriptor_counts[type_index] >
- pool->max.descriptor_counts[type_index]) {
- /* restore pool state before this allocation */
- pool->used = recovery;
- return false;
+ if (type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
+ /* A mutable descriptor can be allocated if below are satisfied:
+ * - vn_descriptor_pool_state_mutable::types is a superset
+ * - vn_descriptor_pool_state_mutable::{max - used} is enough
+ */
+ struct vn_descriptor_pool_state_mutable *mutable_state =
+ vn_find_mutable_state_for_binding(
+ pool, &layout->bindings[binding_index]);
+
+ if (mutable_state &&
+ mutable_state->max - mutable_state->used >= count) {
+ mutable_state->used += count;
+ } else
+ goto fail;
+ } else {
+ const uint32_t type_index = vn_descriptor_type_index(type);
+ pool->used.descriptor_counts[type_index] += count;
+
+ if (pool->used.descriptor_counts[type_index] >
+ pool->max.descriptor_counts[type_index])
+ goto fail;
}
+ binding_index++;
}
return true;
+
+fail:
+ /* restore pool state before this allocation */
+ pool->used = recovery;
+ vn_pool_restore_mutable_states(pool, layout, binding_index - 1,
+ last_binding_descriptor_count);
+ return false;
}
static void
if (!pool->async_set_allocation)
return;
+ vn_pool_restore_mutable_states(pool, layout, layout->last_binding,
+ last_binding_descriptor_count);
+
for (uint32_t i = 0; i <= layout->last_binding; i++) {
const uint32_t count = i == layout->last_binding
? last_binding_descriptor_count
: layout->bindings[i].count;
- pool->used.descriptor_counts[vn_descriptor_type_index(
- layout->bindings[i].type)] -= count;
+ if (layout->bindings[i].type != VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
+ pool->used.descriptor_counts[vn_descriptor_type_index(
+ layout->bindings[i].type)] -= count;
- if (layout->bindings[i].type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
- --pool->used.iub_binding_count;
+ if (layout->bindings[i].type ==
+ VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
+ --pool->used.iub_binding_count;
+ }
}
--pool->used.set_count;
write->pTexelBufferView = NULL;
break;
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
+ case VK_DESCRIPTOR_TYPE_MUTABLE_VALVE:
default:
write->pImageInfo = NULL;
write->pBufferInfo = NULL;