+#include <msp/core/algorithm.h>
+#include "descriptorpool.h"
+#include "device.h"
+#include "pipelinestate.h"
+#include "vulkan.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+DescriptorPool::DescriptorPool(Device &d):
+ device(d)
+{
+ add_pool(increment);
+}
+
+DescriptorPool::~DescriptorPool()
+{
+ const VulkanFunctions &vk = device.get_functions();
+
+ for(VkDescriptorPool p: pools)
+ vk.DestroyDescriptorPool(p);
+}
+
+void DescriptorPool::add_pool(const Counts &counts)
+{
+ const VulkanFunctions &vk = device.get_functions();
+
+ VkDescriptorPoolSize pool_sizes[2] = { };
+ pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ pool_sizes[0].descriptorCount = counts.buffers;
+ pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ pool_sizes[1].descriptorCount = counts.images;
+
+ VkDescriptorPoolCreateInfo pool_info = { };
+ pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ pool_info.maxSets = counts.sets;
+ pool_info.poolSizeCount = 2;
+ pool_info.pPoolSizes = pool_sizes;
+
+ VkDescriptorPool pool;
+ vk.CreateDescriptorPool(pool_info, pool);
+ pools.push_back(pool);
+}
+
+void DescriptorPool::begin_frame()
+{
+ if(pools.size()>1)
+ {
+ DestroyQueue &dq = device.get_destroy_queue();
+ for(VkDescriptorPool p: pools)
+ dq.destroy(p);
+ pools.clear();
+
+ Counts capacity = used;
+ capacity += increment;
+ add_pool(capacity);
+
+ for(auto &s: sets)
+ fill(s.begin(), s.end(), static_cast<VkDescriptorSet>(0));
+
+ used = Counts();
+ }
+}
+
+unsigned DescriptorPool::get_descriptor_set_slot(const PipelineState &ps, unsigned index)
+{
+ unsigned slot;
+
+ uint64_t hash = ps.compute_descriptor_set_hash(index);
+ auto i = lower_bound_member(slots, hash, &HashSlot::hash);
+ if(i!=slots.end() && i->hash==hash)
+ slot = i->slot;
+ else
+ {
+ slot = next_slot++;
+ slots.emplace(i, hash, slot);
+ for(auto &s: sets)
+ s.push_back(0);
+ }
+
+ if(ps.is_descriptor_set_dynamic(index))
+ slot |= DYNAMIC_SLOT;
+ return slot;
+}
+
+VkDescriptorSet DescriptorPool::get_descriptor_set(unsigned slot, const PipelineState &ps, unsigned index, unsigned frame)
+{
+ if(!(slot&DYNAMIC_SLOT))
+ frame = 0;
+ slot &= ~DYNAMIC_SLOT;
+
+ while(sets.size()<=frame)
+ sets.emplace_back(slots.size());
+
+ VkDescriptorSet &desc_set = sets[frame][slot];
+ if(desc_set)
+ return desc_set;
+
+ const VulkanFunctions &vk = device.get_functions();
+
+ Counts alloc;
+ alloc.sets = 1;
+
+ vector<char> buffer;
+ unsigned n_writes = ps.fill_descriptor_writes(index, frame, buffer);
+ VkWriteDescriptorSet *writes = reinterpret_cast<VkWriteDescriptorSet *>(buffer.data());
+ for(unsigned i=0; i<n_writes; ++i)
+ {
+ if(writes[i].descriptorType==VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
+ ++alloc.buffers;
+ if(writes[i].descriptorType==VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+ ++alloc.images;
+ }
+
+ used += alloc;
+
+ VkDescriptorSetLayout layout = ps.get_descriptor_set_layout(index);
+
+ VkDescriptorSetAllocateInfo alloc_info = { };
+ alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ alloc_info.descriptorPool = handle_cast<::VkDescriptorPool>(pools.back());
+ alloc_info.descriptorSetCount = 1;
+ alloc_info.pSetLayouts = handle_cast<::VkDescriptorSetLayout *>(&layout);
+
+ Result result = vk.AllocateDescriptorSets(alloc_info, &desc_set);
+ if(result==VK_ERROR_OUT_OF_POOL_MEMORY)
+ {
+ add_pool(increment);
+ alloc_info.descriptorPool = handle_cast<::VkDescriptorPool>(pools.back());
+ vk.AllocateDescriptorSets(alloc_info, &desc_set);
+ }
+
+ for(unsigned i=0; i<n_writes; ++i)
+ writes[i].dstSet = handle_cast<::VkDescriptorSet>(desc_set);
+
+ vk.UpdateDescriptorSets(n_writes, writes, 0, 0);
+
+ return desc_set;
+}
+
+
+DescriptorPool::Counts::Counts(unsigned s, unsigned b, unsigned i):
+ sets(s),
+ buffers(b),
+ images(i)
+{ }
+
+DescriptorPool::Counts &DescriptorPool::Counts::operator+=(const DescriptorPool::Counts &c)
+{
+ sets += c.sets;
+ buffers += c.buffers;
+ images += c.images;
+ return *this;
+}
+
+} // namespace GL
+} // namespace Msp