HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
gfx_device_vulkan.hpp
1// Copyright Take Vos 2019-2020.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "gfx_device.hpp"
8#include "gfx_system_globals.hpp"
9#include "gfx_queue_vulkan.hpp"
10#include "pipeline_image_device_shared.hpp"
11#include "pipeline_box_device_shared.hpp"
12#include "pipeline_SDF_device_shared.hpp"
13#include "pipeline_tone_mapper_device_shared.hpp"
14#include <vulkan/vulkan.hpp>
15#include <vk_mem_alloc.h>
16
17namespace hi::inline v1 {
18class URL;
19
20class gfx_device_vulkan final : public gfx_device {
21public:
22 vk::PhysicalDeviceType deviceType = vk::PhysicalDeviceType::eOther;
23 vk::PhysicalDeviceProperties physicalProperties;
24
26
29 vk::PhysicalDeviceFeatures device_features;
30
34 [[nodiscard]] gfx_queue_vulkan const &get_graphics_queue() const noexcept;
35
40 [[nodiscard]] gfx_queue_vulkan const &get_graphics_queue(gfx_surface const &surface) const noexcept;
41
46 [[nodiscard]] gfx_queue_vulkan const &get_present_queue(gfx_surface const &surface) const noexcept;
47
56 [[nodiscard]] vk::SurfaceFormatKHR get_surface_format(gfx_surface const &surface, int *score = nullptr) const noexcept;
57
66 [[nodiscard]] vk::PresentModeKHR get_present_mode(gfx_surface const &surface, int *score = nullptr) const noexcept;
67
78 vk::Buffer quadIndexBuffer;
79 VmaAllocation quadIndexBufferAllocation = {};
80
85
89
90 bool supportsLazyTransientImages = false;
91 vk::ImageUsageFlags transientImageUsageFlags = vk::ImageUsageFlags{};
92 VmaMemoryUsage lazyMemoryUsage = VMA_MEMORY_USAGE_GPU_ONLY;
93
94 gfx_device_vulkan(gfx_system &system, vk::PhysicalDevice physicalDevice);
96
97 gfx_device_vulkan(const gfx_device_vulkan &) = delete;
98 gfx_device_vulkan &operator=(const gfx_device_vulkan &) = delete;
100 gfx_device_vulkan &operator=(gfx_device_vulkan &&) = delete;
101
102 int score(vk::SurfaceKHR surface) const;
103
104 int score(gfx_surface const &surface) const override;
105
114
116 createBuffer(const vk::BufferCreateInfo &bufferCreateInfo, const VmaAllocationCreateInfo &allocationCreateInfo) const;
117
118 void destroyBuffer(const vk::Buffer &buffer, const VmaAllocation &allocation) const;
119
121 createImage(const vk::ImageCreateInfo &imageCreateInfo, const VmaAllocationCreateInfo &allocationCreateInfo) const;
122 void destroyImage(const vk::Image &image, const VmaAllocation &allocation) const;
123
124 vk::CommandBuffer beginSingleTimeCommands() const;
125 void endSingleTimeCommands(vk::CommandBuffer commandBuffer) const;
126
127 static void transition_layout(
128 vk::CommandBuffer command_buffer,
129 vk::Image image,
130 vk::Format format,
131 vk::ImageLayout src_layout,
132 vk::ImageLayout dst_layout);
133 void transition_layout(vk::Image image, vk::Format format, vk::ImageLayout src_layout, vk::ImageLayout dst_layout) const;
134
135 void copyImage(
136 vk::Image srcImage,
137 vk::ImageLayout srcLayout,
138 vk::Image dstImage,
139 vk::ImageLayout dstLayout,
140 vk::ArrayProxy<vk::ImageCopy const> regions) const;
141 void clearColorImage(
142 vk::Image image,
143 vk::ImageLayout layout,
144 vk::ClearColorValue const &color,
145 vk::ArrayProxy<const vk::ImageSubresourceRange> ranges) const;
146
147 template<typename T>
148 std::span<T> mapMemory(const VmaAllocation &allocation) const
149 {
150 hi_axiom(gfx_system_mutex.recurse_lock_count());
151
152 void *mapping;
153 hilet result = static_cast<vk::Result>(vmaMapMemory(allocator, allocation, &mapping));
154
155 VmaAllocationInfo allocationInfo;
156 vmaGetAllocationInfo(allocator, allocation, &allocationInfo);
157
158 // Should we launder the pointer? The GPU has created the objects, not the C++ application.
159 T *mappingT = reinterpret_cast<T *>(mapping);
160 hilet mappingSpan = std::span<T>(mappingT, allocationInfo.size / sizeof(T));
161
162 return vk::createResultValue(result, mappingSpan, "hi::gfx_device_vulkan::mapMemory");
163 }
164
165 void unmapMemory(const VmaAllocation &allocation) const;
166
167 void flushAllocation(const VmaAllocation &allocation, VkDeviceSize offset, VkDeviceSize size) const
168 {
169 hi_axiom(gfx_system_mutex.recurse_lock_count());
170
171 hilet alignment = physicalProperties.limits.nonCoherentAtomSize;
172
173 hilet alignedOffset = (offset / alignment) * alignment;
174 hilet adjustedSize = size + (offset - alignedOffset);
175 hilet alignedSize = ((adjustedSize + (alignment - 1)) / alignment) * alignment;
176
177 vmaFlushAllocation(allocator, allocation, alignedOffset, alignedSize);
178 }
179
180 vk::ShaderModule loadShader(uint32_t const *data, std::size_t size) const;
181
182 vk::ShaderModule loadShader(std::span<std::byte const> shaderObjectBytes) const;
183
184 vk::ShaderModule loadShader(URL const &shaderObjectLocation) const;
185
186 void waitIdle() const
187 {
188 hi_axiom(gfx_system_mutex.recurse_lock_count());
189 return intrinsic.waitIdle();
190 }
191
192 vk::Result waitForFences(vk::ArrayProxy<const vk::Fence> fences, vk::Bool32 waitAll, uint64_t timeout) const
193 {
194 hi_axiom(gfx_system_mutex.recurse_lock_count());
195 return intrinsic.waitForFences(fences, waitAll, timeout);
196 }
197
198 vk::Result acquireNextImageKHR(
199 vk::SwapchainKHR swapchain,
200 uint64_t timeout,
201 vk::Semaphore semaphore,
202 vk::Fence fence,
203 uint32_t *pImageIndex) const
204 {
205 hi_axiom(gfx_system_mutex.recurse_lock_count());
206 return intrinsic.acquireNextImageKHR(swapchain, timeout, semaphore, fence, pImageIndex);
207 }
208
209 void resetFences(vk::ArrayProxy<const vk::Fence> fences) const
210 {
211 hi_axiom(gfx_system_mutex.recurse_lock_count());
212 return intrinsic.resetFences(fences);
213 }
214
215 vk::Result createSwapchainKHR(
216 const vk::SwapchainCreateInfoKHR *pCreateInfo,
217 const vk::AllocationCallbacks *pAllocator,
218 vk::SwapchainKHR *pSwapchain) const
219 {
220 hi_axiom(gfx_system_mutex.recurse_lock_count());
221 return intrinsic.createSwapchainKHR(pCreateInfo, pAllocator, pSwapchain);
222 }
223
224 std::vector<vk::Image> getSwapchainImagesKHR(vk::SwapchainKHR swapchain) const
225 {
226 hi_axiom(gfx_system_mutex.recurse_lock_count());
227 return intrinsic.getSwapchainImagesKHR(swapchain);
228 }
229
230 vk::ImageView createImageView(const vk::ImageViewCreateInfo &createInfo) const
231 {
232 hi_axiom(gfx_system_mutex.recurse_lock_count());
233 return intrinsic.createImageView(createInfo);
234 }
235
236 vk::Framebuffer createFramebuffer(const vk::FramebufferCreateInfo &createInfo) const
237 {
238 hi_axiom(gfx_system_mutex.recurse_lock_count());
239 return intrinsic.createFramebuffer(createInfo);
240 }
241
242 vk::RenderPass createRenderPass(const vk::RenderPassCreateInfo &createInfo) const
243 {
244 hi_axiom(gfx_system_mutex.recurse_lock_count());
245 return intrinsic.createRenderPass(createInfo);
246 }
247
248 vk::Extent2D getRenderAreaGranularity(const vk::RenderPass &render_pass) const noexcept
249 {
250 hi_axiom(gfx_system_mutex.recurse_lock_count());
251 vk::Extent2D r;
252 intrinsic.getRenderAreaGranularity(render_pass, &r);
253 return r;
254 }
255
256 vk::Semaphore createSemaphore(const vk::SemaphoreCreateInfo &createInfo) const
257 {
258 hi_axiom(gfx_system_mutex.recurse_lock_count());
259 return intrinsic.createSemaphore(createInfo);
260 }
261
262 vk::Fence createFence(const vk::FenceCreateInfo &createInfo) const
263 {
264 hi_axiom(gfx_system_mutex.recurse_lock_count());
265 return intrinsic.createFence(createInfo);
266 }
267
268 vk::DescriptorSetLayout createDescriptorSetLayout(const vk::DescriptorSetLayoutCreateInfo &createInfo) const
269 {
270 hi_axiom(gfx_system_mutex.recurse_lock_count());
271 return intrinsic.createDescriptorSetLayout(createInfo);
272 }
273
274 vk::DescriptorPool createDescriptorPool(const vk::DescriptorPoolCreateInfo &createInfo) const
275 {
276 hi_axiom(gfx_system_mutex.recurse_lock_count());
277 return intrinsic.createDescriptorPool(createInfo);
278 }
279
280 vk::PipelineLayout createPipelineLayout(const vk::PipelineLayoutCreateInfo &createInfo) const
281 {
282 hi_axiom(gfx_system_mutex.recurse_lock_count());
283 return intrinsic.createPipelineLayout(createInfo);
284 }
285
286 vk::Pipeline createGraphicsPipeline(vk::PipelineCache pipelineCache, const vk::GraphicsPipelineCreateInfo &createInfo) const
287 {
288 hi_axiom(gfx_system_mutex.recurse_lock_count());
289 return intrinsic.createGraphicsPipeline(pipelineCache, createInfo).value;
290 }
291
292 vk::Sampler createSampler(const vk::SamplerCreateInfo &createInfo) const
293 {
294 hi_axiom(gfx_system_mutex.recurse_lock_count());
295 return intrinsic.createSampler(createInfo);
296 }
297
298 std::vector<vk::DescriptorSet> allocateDescriptorSets(const vk::DescriptorSetAllocateInfo &allocateInfo) const
299 {
300 hi_axiom(gfx_system_mutex.recurse_lock_count());
301 return intrinsic.allocateDescriptorSets(allocateInfo);
302 }
303
304 std::vector<vk::CommandBuffer> allocateCommandBuffers(const vk::CommandBufferAllocateInfo &allocateInfo) const
305 {
306 hi_axiom(gfx_system_mutex.recurse_lock_count());
307 return intrinsic.allocateCommandBuffers(allocateInfo);
308 }
309
310 void updateDescriptorSets(
311 vk::ArrayProxy<const vk::WriteDescriptorSet> descriptorWrites,
312 vk::ArrayProxy<const vk::CopyDescriptorSet> descriptorCopies) const
313 {
314 hi_axiom(gfx_system_mutex.recurse_lock_count());
315 return intrinsic.updateDescriptorSets(descriptorWrites, descriptorCopies);
316 }
317
318 void freeCommandBuffers(vk::CommandPool commandPool, vk::ArrayProxy<const vk::CommandBuffer> commandBuffers) const
319 {
320 hi_axiom(gfx_system_mutex.recurse_lock_count());
321 return intrinsic.freeCommandBuffers(commandPool, commandBuffers);
322 }
323
324 void setDebugUtilsObjectNameEXT(vk::DebugUtilsObjectNameInfoEXT const &name_info) const;
325
326 void setDebugUtilsObjectNameEXT(vk::Image image, char const *name) const
327 {
328 return setDebugUtilsObjectNameEXT(
329 vk::DebugUtilsObjectNameInfoEXT{vk::ObjectType::eImage, std::bit_cast<uint64_t>(image), name});
330 }
331
332 void setDebugUtilsObjectNameEXT(vk::Buffer buffer, char const *name) const
333 {
334 return setDebugUtilsObjectNameEXT(
335 vk::DebugUtilsObjectNameInfoEXT{vk::ObjectType::eBuffer, std::bit_cast<uint64_t>(buffer), name});
336 }
337
338 void setDebugUtilsObjectNameEXT(vk::Sampler sampler, char const *name) const
339 {
340 return setDebugUtilsObjectNameEXT(
341 vk::DebugUtilsObjectNameInfoEXT{vk::ObjectType::eSampler, std::bit_cast<uint64_t>(sampler), name});
342 }
343
344 void setDebugUtilsObjectNameEXT(vk::ShaderModule shader_module, char const *name) const
345 {
346 return setDebugUtilsObjectNameEXT(
347 vk::DebugUtilsObjectNameInfoEXT{vk::ObjectType::eShaderModule, std::bit_cast<uint64_t>(shader_module), name});
348 }
349
350 void cmdBeginDebugUtilsLabelEXT(vk::CommandBuffer buffer, vk::DebugUtilsLabelEXT const &create_info) const;
351 void cmdEndDebugUtilsLabelEXT(vk::CommandBuffer buffer) const;
352
353 void cmdBeginDebugUtilsLabelEXT(vk::CommandBuffer buffer, char const *name) const
354 {
355 return cmdBeginDebugUtilsLabelEXT(buffer, vk::DebugUtilsLabelEXT{name});
356 }
357
358 template<typename T>
359 void destroy(T x) const
360 {
361 hi_axiom(gfx_system_mutex.recurse_lock_count());
362 intrinsic.destroy(x);
363 }
364
365 vk::SurfaceCapabilitiesKHR getSurfaceCapabilitiesKHR(vk::SurfaceKHR surface) const
366 {
367 hi_axiom(gfx_system_mutex.recurse_lock_count());
368 return physicalIntrinsic.getSurfaceCapabilitiesKHR(surface);
369 }
370
371 void log_memory_usage() const noexcept override;
372
373protected:
374 vk::PhysicalDevice physicalIntrinsic;
375 vk::Device intrinsic;
376 VmaAllocator allocator;
377
378private:
379 [[nodiscard]] std::vector<vk::DeviceQueueCreateInfo> make_device_queue_create_infos() const noexcept;
380 void initialize_queues(std::vector<vk::DeviceQueueCreateInfo> const &device_queue_create_infos) noexcept;
381 void initialize_device();
382 void initialize_quad_index_buffer();
383 void destroy_quad_index_buffer();
384};
385
386} // namespace hi::inline v1
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
STL namespace.
Definition alignment.hpp:64
This is a RGBA floating point color.
Definition color.hpp:37
Definition gfx_device.hpp:22
Definition gfx_device_vulkan.hpp:20
std::vector< const char * > requiredExtensions
Definition gfx_device_vulkan.hpp:88
gfx_queue_vulkan const & get_graphics_queue() const noexcept
Get a graphics queue.
vk::PhysicalDeviceFeatures device_features
The device features that have been turned on for this device.
Definition gfx_device_vulkan.hpp:29
int score(gfx_surface const &surface) const override
std::vector< std::pair< uint32_t, uint8_t > > find_best_queue_family_indices(vk::SurfaceKHR surface) const
Definition gfx_queue_vulkan.hpp:12
Definition gfx_surface.hpp:15
Graphics system.
Definition gfx_system.hpp:21
int recurse_lock_count() const noexcept
This function should be used in hi_axiom() to check if the lock is held by current thread.
Definition unfair_recursive_mutex.hpp:60