1 /* Copyright (c) 2017-2018 Hans-Kristian Arntzen
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be
12  * included in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #pragma once
24 
25 #include "hash.hpp"
26 #include "object_pool.hpp"
27 #include "temporary_hashmap.hpp"
28 #include "vulkan.hpp"
29 #include "sampler.hpp"
30 #include <utility>
31 #include <vector>
32 #include "cookie.hpp"
33 
34 namespace Vulkan
35 {
36 class Device;
37 struct DescriptorSetLayout
38 {
39 	uint32_t sampled_image_mask = 0;
40 	uint32_t storage_image_mask = 0;
41 	uint32_t uniform_buffer_mask = 0;
42 	uint32_t storage_buffer_mask = 0;
43 	uint32_t sampled_buffer_mask = 0;
44 	uint32_t input_attachment_mask = 0;
45 	uint32_t sampler_mask = 0;
46 	uint32_t separate_image_mask = 0;
47 	uint32_t fp_mask = 0;
48 	uint32_t immutable_sampler_mask = 0;
49 	uint64_t immutable_samplers = 0;
50 };
51 
52 // Avoid -Wclass-memaccess warnings since we hash DescriptorSetLayout.
53 
has_immutable_sampler(const DescriptorSetLayout & layout,unsigned binding)54 static inline bool has_immutable_sampler(const DescriptorSetLayout &layout, unsigned binding)
55 {
56 	return (layout.immutable_sampler_mask & (1u << binding)) != 0;
57 }
58 
get_immutable_sampler(const DescriptorSetLayout & layout,unsigned binding)59 static inline StockSampler get_immutable_sampler(const DescriptorSetLayout &layout, unsigned binding)
60 {
61 	VK_ASSERT(has_immutable_sampler(layout, binding));
62 	return static_cast<StockSampler>((layout.immutable_samplers >> (4 * binding)) & 0xf);
63 }
64 
set_immutable_sampler(DescriptorSetLayout & layout,unsigned binding,StockSampler sampler)65 static inline void set_immutable_sampler(DescriptorSetLayout &layout, unsigned binding, StockSampler sampler)
66 {
67 	layout.immutable_samplers |= uint64_t(sampler) << (4 * binding);
68 	layout.immutable_sampler_mask |= 1u << binding;
69 }
70 
71 static const unsigned VULKAN_NUM_SETS_PER_POOL = 16;
72 static const unsigned VULKAN_DESCRIPTOR_RING_SIZE = 8;
73 
74 class DescriptorSetAllocator : public HashedObject<DescriptorSetAllocator>
75 {
76 public:
77 	DescriptorSetAllocator(Util::Hash hash, Device *device, const DescriptorSetLayout &layout, const uint32_t *stages_for_bindings);
78 	~DescriptorSetAllocator();
79 	void operator=(const DescriptorSetAllocator &) = delete;
80 	DescriptorSetAllocator(const DescriptorSetAllocator &) = delete;
81 
82 	void begin_frame();
83 	std::pair<VkDescriptorSet, bool> find(unsigned thread_index, Util::Hash hash);
84 
get_layout() const85 	VkDescriptorSetLayout get_layout() const
86 	{
87 		return set_layout;
88 	}
89 
90 	void clear();
91 
92 private:
93 	struct DescriptorSetNode : Util::TemporaryHashmapEnabled<DescriptorSetNode>, Util::IntrusiveListEnabled<DescriptorSetNode>
94 	{
DescriptorSetNodeVulkan::DescriptorSetAllocator::DescriptorSetNode95 		DescriptorSetNode(VkDescriptorSet set)
96 		    : set(set)
97 		{
98 		}
99 
100 		VkDescriptorSet set;
101 	};
102 
103 	Device *device;
104 	VkDescriptorSetLayout set_layout = VK_NULL_HANDLE;
105 
106 	struct PerThread
107 	{
108 		Util::TemporaryHashmap<DescriptorSetNode, VULKAN_DESCRIPTOR_RING_SIZE, true> set_nodes;
109 		std::vector<VkDescriptorPool> pools;
110 		bool should_begin = true;
111 	};
112 	std::vector<std::unique_ptr<PerThread>> per_thread;
113 	std::vector<VkDescriptorPoolSize> pool_size;
114 };
115 }
116