HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
gfx_device_vulkan.hpp
1// Copyright Take Vos 2019-2022.
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_alpha_device_shared.hpp"
14#include "pipeline_tone_mapper_device_shared.hpp"
15#include <vulkan/vulkan.hpp>
16#include <vma/vk_mem_alloc.h>
17#include <filesystem>
18
19namespace hi::inline v1 {
20
21class gfx_device_vulkan final : public gfx_device {
22public:
23 vk::PhysicalDevice physicalIntrinsic;
24 vk::Device intrinsic;
25 VmaAllocator allocator;
26
27 vk::PhysicalDeviceType deviceType = vk::PhysicalDeviceType::eOther;
28 vk::PhysicalDeviceProperties physicalProperties;
29
31
34 vk::PhysicalDeviceFeatures device_features;
35
39 [[nodiscard]] gfx_queue_vulkan const &get_graphics_queue() const noexcept;
40
45 [[nodiscard]] gfx_queue_vulkan const &get_graphics_queue(gfx_surface const &surface) const noexcept;
46
51 [[nodiscard]] gfx_queue_vulkan const &get_present_queue(gfx_surface const &surface) const noexcept;
52
61 [[nodiscard]] vk::SurfaceFormatKHR get_surface_format(gfx_surface const &surface, int *score = nullptr) const noexcept;
62
71 [[nodiscard]] vk::PresentModeKHR get_present_mode(gfx_surface const &surface, int *score = nullptr) const noexcept;
72
83 vk::Buffer quadIndexBuffer;
84 VmaAllocation quadIndexBufferAllocation = {};
85
91
95
96 bool supportsLazyTransientImages = false;
97 vk::ImageUsageFlags transientImageUsageFlags = vk::ImageUsageFlags{};
98 VmaMemoryUsage lazyMemoryUsage = VMA_MEMORY_USAGE_GPU_ONLY;
99
100 gfx_device_vulkan(gfx_system &system, vk::PhysicalDevice physicalDevice);
102
103 gfx_device_vulkan(const gfx_device_vulkan &) = delete;
104 gfx_device_vulkan &operator=(const gfx_device_vulkan &) = delete;
106 gfx_device_vulkan &operator=(gfx_device_vulkan &&) = delete;
107
108 int score(vk::SurfaceKHR surface) const;
109
110 int score(gfx_surface const &surface) const override;
111
120
122 createBuffer(const vk::BufferCreateInfo &bufferCreateInfo, const VmaAllocationCreateInfo &allocationCreateInfo) const;
123
124 void destroyBuffer(const vk::Buffer &buffer, const VmaAllocation &allocation) const;
125
127 createImage(const vk::ImageCreateInfo &imageCreateInfo, const VmaAllocationCreateInfo &allocationCreateInfo) const;
128 void destroyImage(const vk::Image &image, const VmaAllocation &allocation) const;
129
130 vk::CommandBuffer beginSingleTimeCommands() const;
131 void endSingleTimeCommands(vk::CommandBuffer commandBuffer) const;
132
133 static void transition_layout(
134 vk::CommandBuffer command_buffer,
135 vk::Image image,
136 vk::Format format,
137 vk::ImageLayout src_layout,
138 vk::ImageLayout dst_layout);
139 void transition_layout(vk::Image image, vk::Format format, vk::ImageLayout src_layout, vk::ImageLayout dst_layout) const;
140
141 void copyImage(
142 vk::Image srcImage,
143 vk::ImageLayout srcLayout,
144 vk::Image dstImage,
145 vk::ImageLayout dstLayout,
146 vk::ArrayProxy<vk::ImageCopy const> regions) const;
147 void clearColorImage(
148 vk::Image image,
149 vk::ImageLayout layout,
150 vk::ClearColorValue const &color,
151 vk::ArrayProxy<const vk::ImageSubresourceRange> ranges) const;
152
153 template<typename T>
154 std::span<T> mapMemory(const VmaAllocation &allocation) const
155 {
157
158 void *mapping;
159 hilet result = vk::Result{vmaMapMemory(allocator, allocation, &mapping)};
160 if (result != vk::Result::eSuccess) {
161 throw gui_error(std::format("vmaMapMemory failed {}", to_string(result)));
162 }
163
164 VmaAllocationInfo allocationInfo;
165 vmaGetAllocationInfo(allocator, allocation, &allocationInfo);
166
167 // Should we launder the pointer? The GPU has created the objects, not the C++ application.
168 T *mappingT = reinterpret_cast<T *>(mapping);
169 return std::span<T>{mappingT, allocationInfo.size / sizeof(T)};
170 }
171
172 void unmapMemory(const VmaAllocation &allocation) const;
173
174 void flushAllocation(const VmaAllocation &allocation, VkDeviceSize offset, VkDeviceSize size) const
175 {
177
178 hilet alignment = physicalProperties.limits.nonCoherentAtomSize;
179
180 hilet alignedOffset = (offset / alignment) * alignment;
181 hilet adjustedSize = size + (offset - alignedOffset);
182 hilet alignedSize = ((adjustedSize + (alignment - 1)) / alignment) * alignment;
183
184 vmaFlushAllocation(allocator, allocation, alignedOffset, alignedSize);
185 }
186
187 vk::ShaderModule loadShader(uint32_t const *data, std::size_t size) const;
188
189 vk::ShaderModule loadShader(std::span<std::byte const> shaderObjectBytes) const;
190
191 vk::ShaderModule loadShader(std::filesystem::path const &path) const;
192
193 void waitIdle() const
194 {
196 return intrinsic.waitIdle();
197 }
198
199 vk::Result waitForFences(vk::ArrayProxy<const vk::Fence> fences, vk::Bool32 waitAll, uint64_t timeout) const
200 {
202 return intrinsic.waitForFences(fences, waitAll, timeout);
203 }
204
205 vk::Result acquireNextImageKHR(
206 vk::SwapchainKHR swapchain,
207 uint64_t timeout,
208 vk::Semaphore semaphore,
209 vk::Fence fence,
210 uint32_t *pImageIndex) const
211 {
213 return intrinsic.acquireNextImageKHR(swapchain, timeout, semaphore, fence, pImageIndex);
214 }
215
216 void resetFences(vk::ArrayProxy<const vk::Fence> fences) const
217 {
219 return intrinsic.resetFences(fences);
220 }
221
222 vk::Result createSwapchainKHR(
223 const vk::SwapchainCreateInfoKHR *pCreateInfo,
224 const vk::AllocationCallbacks *pAllocator,
225 vk::SwapchainKHR *pSwapchain) const
226 {
228 return intrinsic.createSwapchainKHR(pCreateInfo, pAllocator, pSwapchain);
229 }
230
231 std::vector<vk::Image> getSwapchainImagesKHR(vk::SwapchainKHR swapchain) const
232 {
234 return intrinsic.getSwapchainImagesKHR(swapchain);
235 }
236
237 vk::ImageView createImageView(const vk::ImageViewCreateInfo &createInfo) const
238 {
240 return intrinsic.createImageView(createInfo);
241 }
242
243 vk::Framebuffer createFramebuffer(const vk::FramebufferCreateInfo &createInfo) const
244 {
246 return intrinsic.createFramebuffer(createInfo);
247 }
248
249 vk::RenderPass createRenderPass(const vk::RenderPassCreateInfo &createInfo) const
250 {
252 return intrinsic.createRenderPass(createInfo);
253 }
254
255 vk::Extent2D getRenderAreaGranularity(const vk::RenderPass &render_pass) const noexcept
256 {
258 vk::Extent2D r;
259 intrinsic.getRenderAreaGranularity(render_pass, &r);
260 return r;
261 }
262
263 vk::Semaphore createSemaphore(const vk::SemaphoreCreateInfo& createInfo = vk::SemaphoreCreateInfo{}) const
264 {
266 return intrinsic.createSemaphore(createInfo);
267 }
268
269 vk::Fence createFence(const vk::FenceCreateInfo &createInfo) const
270 {
272 return intrinsic.createFence(createInfo);
273 }
274
275 vk::DescriptorSetLayout createDescriptorSetLayout(const vk::DescriptorSetLayoutCreateInfo &createInfo) const
276 {
278 return intrinsic.createDescriptorSetLayout(createInfo);
279 }
280
281 vk::DescriptorPool createDescriptorPool(const vk::DescriptorPoolCreateInfo &createInfo) const
282 {
284 return intrinsic.createDescriptorPool(createInfo);
285 }
286
287 vk::PipelineLayout createPipelineLayout(const vk::PipelineLayoutCreateInfo &createInfo) const
288 {
290 return intrinsic.createPipelineLayout(createInfo);
291 }
292
293 vk::Pipeline createGraphicsPipeline(vk::PipelineCache pipelineCache, const vk::GraphicsPipelineCreateInfo &createInfo) const
294 {
296 return intrinsic.createGraphicsPipeline(pipelineCache, createInfo).value;
297 }
298
299 vk::Sampler createSampler(const vk::SamplerCreateInfo &createInfo) const
300 {
302 return intrinsic.createSampler(createInfo);
303 }
304
305 std::vector<vk::DescriptorSet> allocateDescriptorSets(const vk::DescriptorSetAllocateInfo &allocateInfo) const
306 {
308 return intrinsic.allocateDescriptorSets(allocateInfo);
309 }
310
311 std::vector<vk::CommandBuffer> allocateCommandBuffers(const vk::CommandBufferAllocateInfo &allocateInfo) const
312 {
314 return intrinsic.allocateCommandBuffers(allocateInfo);
315 }
316
317 void updateDescriptorSets(
318 vk::ArrayProxy<const vk::WriteDescriptorSet> descriptorWrites,
319 vk::ArrayProxy<const vk::CopyDescriptorSet> descriptorCopies) const
320 {
322 return intrinsic.updateDescriptorSets(descriptorWrites, descriptorCopies);
323 }
324
325 void freeCommandBuffers(vk::CommandPool commandPool, vk::ArrayProxy<const vk::CommandBuffer> commandBuffers) const
326 {
328 return intrinsic.freeCommandBuffers(commandPool, commandBuffers);
329 }
330
331 void setDebugUtilsObjectNameEXT(vk::DebugUtilsObjectNameInfoEXT const &name_info) const;
332
333 void setDebugUtilsObjectNameEXT(vk::Image image, char const *name) const
334 {
335 return setDebugUtilsObjectNameEXT(
336 vk::DebugUtilsObjectNameInfoEXT{vk::ObjectType::eImage, std::bit_cast<uint64_t>(image), name});
337 }
338
339 void setDebugUtilsObjectNameEXT(vk::Buffer buffer, char const *name) const
340 {
341 return setDebugUtilsObjectNameEXT(
342 vk::DebugUtilsObjectNameInfoEXT{vk::ObjectType::eBuffer, std::bit_cast<uint64_t>(buffer), name});
343 }
344
345 void setDebugUtilsObjectNameEXT(vk::Sampler sampler, char const *name) const
346 {
347 return setDebugUtilsObjectNameEXT(
348 vk::DebugUtilsObjectNameInfoEXT{vk::ObjectType::eSampler, std::bit_cast<uint64_t>(sampler), name});
349 }
350
351 void setDebugUtilsObjectNameEXT(vk::ShaderModule shader_module, char const *name) const
352 {
353 return setDebugUtilsObjectNameEXT(
354 vk::DebugUtilsObjectNameInfoEXT{vk::ObjectType::eShaderModule, std::bit_cast<uint64_t>(shader_module), name});
355 }
356
357 void cmdBeginDebugUtilsLabelEXT(vk::CommandBuffer buffer, vk::DebugUtilsLabelEXT const &create_info) const;
358 void cmdEndDebugUtilsLabelEXT(vk::CommandBuffer buffer) const;
359
360 void cmdBeginDebugUtilsLabelEXT(vk::CommandBuffer buffer, char const *name) const
361 {
362 return cmdBeginDebugUtilsLabelEXT(buffer, vk::DebugUtilsLabelEXT{name});
363 }
364
365 template<typename T>
366 void destroy(T x) const
367 {
369 intrinsic.destroy(x);
370 }
371
372 vk::SurfaceCapabilitiesKHR getSurfaceCapabilitiesKHR(vk::SurfaceKHR surface) const
373 {
375 return physicalIntrinsic.getSurfaceCapabilitiesKHR(surface);
376 }
377
378 void log_memory_usage() const noexcept override;
379
380
381private:
382 [[nodiscard]] std::vector<vk::DeviceQueueCreateInfo> make_device_queue_create_infos() const noexcept;
383 void initialize_queues(std::vector<vk::DeviceQueueCreateInfo> const &device_queue_create_infos) noexcept;
384 void initialize_device();
385 void initialize_quad_index_buffer();
386 void destroy_quad_index_buffer();
387};
388
389} // namespace hi::inline v1
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:133
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:15
unfair_recursive_mutex gfx_system_mutex
Global mutex for GUI elements, like gfx_system, gfx_device, Windows and Widgets.
Definition gfx_system_globals.hpp:15
This is a RGBA floating point color.
Definition color.hpp:39
Definition gfx_device.hpp:22
Definition gfx_device_vulkan.hpp:21
std::vector< const char * > requiredExtensions
Definition gfx_device_vulkan.hpp:94
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:34
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:16
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