summaryrefslogtreecommitdiffstats
path: root/src/libixion/vulkan_obj.hpp
blob: 498efa82a51b0c193e9966f004013925b85400c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef INCLUDED_IXION_VULKAN_OBJ_HPP
#define INCLUDED_IXION_VULKAN_OBJ_HPP

#include <vulkan/vulkan.h>
#include <memory>
#include <limits>

namespace ixion { namespace draft {

template<typename T, typename U = void>
struct null_value;

template<typename T>
struct null_value<T, typename std::enable_if<std::is_pointer<T>::value>::type>
{
    static constexpr std::nullptr_t value = nullptr;
};

template<typename T>
struct null_value<T, typename std::enable_if<std::is_integral<T>::value>::type>
{
    static constexpr T value = 0;
};

struct runtime_context
{
    uint32_t input_buffer_size = 0;
};

class vk_buffer;
class vk_command_buffer;
class vk_command_pool;
class vk_descriptor_set;
class vk_descriptor_set_layout;
class vk_fence;
class vk_pipeline;
class vk_pipeline_layout;

class vk_instance
{
    VkInstance m_instance = null_value<VkInstance>::value;
    VkDebugUtilsMessengerEXT m_debug_messenger = null_value<VkDebugUtilsMessengerEXT>::value;

public:
    vk_instance();
    ~vk_instance();

    VkInstance& get();
};

class vk_queue
{
    VkQueue m_queue;

public:
    vk_queue(VkQueue queue);
    ~vk_queue();

    void submit(vk_command_buffer& cmd, vk_fence& fence, VkPipelineStageFlags dst_stages = 0);

    void wait_idle();
};

class vk_device
{
    friend class vk_command_pool;
    friend class vk_buffer;

    static constexpr uint32_t QUEUE_FAMILY_NOT_SET = std::numeric_limits<uint32_t>::max();

    VkPhysicalDevice m_physical_device = null_value<VkPhysicalDevice>::value;
    VkPhysicalDeviceProperties m_physical_device_props;
    VkDevice m_device = null_value<VkDevice>::value;
    uint32_t m_queue_family_index = QUEUE_FAMILY_NOT_SET;
    VkQueue m_queue = null_value<VkQueue>::value;

    uint32_t get_queue_family_index() const
    {
        return m_queue_family_index;
    }

public:
    vk_device(vk_instance& instance);
    ~vk_device();

    VkDevice& get();
    const VkDevice& get() const;

    VkPhysicalDevice get_physical_device();

    const VkPhysicalDeviceLimits& get_physical_device_limits() const;

    vk_queue get_queue();
};

class vk_command_pool
{
    friend class vk_command_buffer;

    VkDevice m_device = null_value<VkDevice>::value;
    VkCommandPool m_cmd_pool = null_value<VkCommandPool>::value;

    VkDevice& get_device();
    VkCommandPool& get();

public:
    vk_command_pool(vk_device& device);
    ~vk_command_pool();

    vk_command_buffer create_command_buffer();
};

class vk_command_buffer
{
    friend class vk_command_pool;

    vk_command_pool& m_cmd_pool;
    VkCommandBuffer m_cmd_buffer = null_value<VkCommandBuffer>::value;

    vk_command_buffer(vk_command_pool& cmd_pool);

public:
    ~vk_command_buffer();

    VkCommandBuffer& get();

    void begin();
    void end();

    void copy_buffer(vk_buffer& src, vk_buffer& dst, VkDeviceSize size);

    void buffer_memory_barrier(
        const vk_buffer& buffer, VkAccessFlags src_access, VkAccessFlags dst_access,
        VkPipelineStageFlagBits src_stage, VkPipelineStageFlagBits dst_stage);

    void bind_pipeline(const vk_pipeline& pipeline, VkPipelineBindPoint bind_point);

    void bind_descriptor_set(
        VkPipelineBindPoint bind_point, const vk_pipeline_layout& pl_layout,
        const vk_descriptor_set& desc_set);

    void dispatch(uint32_t gc_x, uint32_t gc_y, uint32_t gc_z);
};

class vk_buffer
{
    vk_device& m_device;
    VkBuffer m_buffer = null_value<VkBuffer>::value;
    VkDeviceMemory m_memory = null_value<VkDeviceMemory>::value;

    struct mem_type
    {
        uint32_t index;
        VkDeviceSize size;
    };

    /**
     * Find a suitable device memory type that can be used to store data for
     * the buffer.
     *
     * @param mem_props desired memory properties.
     *
     * @return mem_type memory type as an index into the list of device memory
     *         types, and the memory size as required by the buffer.
     */
    mem_type find_memory_type(VkMemoryPropertyFlags mem_props) const;

public:
    vk_buffer(vk_device& device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags mem_props);
    ~vk_buffer();

    VkBuffer& get();
    const VkBuffer& get() const;

    void write_to_memory(void* data, VkDeviceSize size);

    void read_from_memory(void* data, VkDeviceSize size);
};

class vk_fence
{
    vk_device& m_device;
    VkFence m_fence = null_value<VkFence>::value;

public:
    vk_fence(vk_device& device, VkFenceCreateFlags flags);
    ~vk_fence();

    VkFence& get();

    void wait();
    void reset();
};

class vk_descriptor_pool
{
    vk_device& m_device;
    VkDescriptorPool m_pool = null_value<VkDescriptorPool>::value;

public:
    vk_descriptor_pool(vk_device& device, uint32_t max_sets, std::initializer_list<VkDescriptorPoolSize> sizes);
    ~vk_descriptor_pool();

    vk_descriptor_set allocate(const vk_descriptor_set_layout& ds_layout);
};

class vk_descriptor_set_layout
{
    vk_device& m_device;
    VkDescriptorSetLayout m_ds_layout = null_value<VkDescriptorSetLayout>::value;

public:
    vk_descriptor_set_layout(vk_device& device, std::initializer_list<VkDescriptorSetLayoutBinding> bindings);
    ~vk_descriptor_set_layout();

    VkDescriptorSetLayout& get();
    const VkDescriptorSetLayout& get() const;
};

/**
 * Descriptor set contains a collection of descriptors. Think of a
 * descriptor as a handle into a resource, which can be a buffer or an
 * image.
 *
 * @see https://vkguide.dev/docs/chapter-4/descriptors/
 *
 */
class vk_descriptor_set
{
    friend class vk_descriptor_pool;
    VkDescriptorSet m_set = null_value<VkDescriptorSet>::value;

    vk_descriptor_set(VkDescriptorSet ds);
public:
    ~vk_descriptor_set();

    VkDescriptorSet& get();
    const VkDescriptorSet& get() const;

    /**
     * Update the descriptor set with the content of the device local buffer.
     *
     * @param device logical device
     * @param binding binding position
     * @param type descriptor type.
     * @param buffer device local buffer to get the content from.
     */
    void update(const vk_device& device, uint32_t binding, VkDescriptorType type, const vk_buffer& buffer);
};

class vk_pipeline_layout
{
    vk_device& m_device;
    VkPipelineLayout m_layout = null_value<VkPipelineLayout>::value;

public:
    vk_pipeline_layout(vk_device& device, vk_descriptor_set_layout& ds_layout);
    ~vk_pipeline_layout();

    VkPipelineLayout& get();
    const VkPipelineLayout& get() const;
};

class vk_pipeline_cache
{
    vk_device& m_device;
    VkPipelineCache m_cache = null_value<VkPipelineCache>::value;

public:
    vk_pipeline_cache(vk_device& device);
    ~vk_pipeline_cache();

    VkPipelineCache& get();
    const VkPipelineCache& get() const;
};

class vk_shader_module
{
    vk_device& m_device;
    VkShaderModule m_module = null_value<VkShaderModule>::value;

public:
    enum class module_type { fibonacci };

    vk_shader_module(vk_device& device, module_type mt);
    ~vk_shader_module();

    VkShaderModule& get();
    const VkShaderModule& get() const;
};

class vk_pipeline
{
    vk_device& m_device;
    VkPipeline m_pipeline = null_value<VkPipeline>::value;

public:
    vk_pipeline(
        const runtime_context& cxt, vk_device& device, vk_pipeline_layout& pl_layout,
        vk_pipeline_cache& pl_cache, vk_shader_module& shader);

    ~vk_pipeline();

    VkPipeline& get();
    const VkPipeline& get() const;
};

}}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */