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