HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
gfx_device_vulkan_impl.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_vulkan_intf.hpp"
8#include "gfx_system_vulkan_intf.hpp"
9#include "gfx_surface_vulkan_intf.hpp"
10#include "../file/file.hpp"
11#include "../utility/utility.hpp"
12#include "../macros.hpp"
13#include <vulkan/vulkan.hpp>
14#include <span>
15
16hi_export_module(hikogui.GFX : gfx_device_impl);
17
18hi_export namespace hi::inline v1 {
19
20inline gfx_device::gfx_device(vk::PhysicalDevice physicalDevice) :
21 physicalIntrinsic(std::move(physicalDevice))
22{
23 auto result = physicalIntrinsic.getProperties2KHR<vk::PhysicalDeviceProperties2, vk::PhysicalDeviceIDProperties>(
24 vulkan_loader());
25
26 auto resultDeviceProperties2 = result.get<vk::PhysicalDeviceProperties2>();
27 auto resultDeviceIDProperties = result.get<vk::PhysicalDeviceIDProperties>();
28
29 requiredExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
30 requiredExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
31 requiredExtensions.push_back(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
32 // requiredExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
33 requiredExtensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
34 requiredExtensions.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
35
36 deviceID = resultDeviceProperties2.properties.deviceID;
37 vendorID = resultDeviceProperties2.properties.vendorID;
38 deviceName = std::string(resultDeviceProperties2.properties.deviceName.data());
39 deviceUUID = uuid::from_big_endian(resultDeviceIDProperties.deviceUUID);
40
41 physicalProperties = physicalIntrinsic.getProperties();
42
43 initialize_device();
44}
45
46inline int gfx_device::score(vk::SurfaceKHR surface) const
47{
48 hi_axiom(gfx_system_mutex.recurse_lock_count());
49
50 auto total_score = 0;
51
52 hi_log_info("Scoring device: {}", string());
53 if (not hasRequiredFeatures(physicalIntrinsic, gfx_system::global().requiredFeatures)) {
54 hi_log_info(" - Does not have the required features.");
55 return -1;
56 }
57
58 if (not meetsRequiredLimits(physicalIntrinsic, gfx_system::global().requiredLimits)) {
59 hi_log_info(" - Does not meet the required limits.");
60 return -1;
61 }
62
63 if (!hasRequiredExtensions(physicalIntrinsic, requiredExtensions)) {
64 hi_log_info(" - Does not have the required extensions.");
65 return -1;
66 }
67
68 bool device_has_graphics = false;
69 bool device_has_present = false;
70 bool device_has_compute = false;
71 bool device_shares_graphics_and_present = false;
72 for (auto const& queue : _queues) {
73 auto const has_present = to_bool(physicalIntrinsic.getSurfaceSupportKHR(queue.family_queue_index, surface));
74 auto const has_graphics = to_bool(queue.flags & vk::QueueFlagBits::eGraphics);
75 auto const has_compute = to_bool(queue.flags & vk::QueueFlagBits::eCompute);
76
77 device_has_graphics |= has_graphics;
78 device_has_present |= has_present;
79 device_has_compute |= has_compute;
80 if (has_present and has_graphics) {
81 device_shares_graphics_and_present = true;
82 }
83 }
84
85 if (not device_has_graphics) {
86 hi_log_info(" - Does not have a graphics queue.");
87 return -1;
88 }
89
90 if (not device_has_present) {
91 hi_log_info(" - Does not have a present queue.");
92 return -1;
93 }
94
95 if (device_has_compute) {
96 hi_log_info(" - Device has compute queue.");
97 total_score += 1;
98 }
99
100 if (device_shares_graphics_and_present) {
101 hi_log_info(" - Device shares graphics and present on same queue.");
102 total_score += 10;
103 }
104
105 hi_log_info(" - Surface formats:");
106 int surface_format_score = 0;
107 [[maybe_unused]] auto surface_format = get_surface_format(surface, &surface_format_score);
108 if (surface_format_score <= 0) {
109 hi_log_info(" - Does not have a suitable surface format.");
110 return -1;
111 }
112 total_score += surface_format_score;
113
114 hi_log_info(" - Present modes:");
115 int present_mode_score = 0;
116 [[maybe_unused]] auto present_mode = get_present_mode(surface, &present_mode_score);
117 if (present_mode_score <= 0) {
118 hi_log_info(" - Does not have a suitable present mode.");
119 return -1;
120 }
121 total_score += present_mode_score;
122
123 // Give score based on the performance of the device.
124 auto device_type_score = 0;
125 auto const properties = physicalIntrinsic.getProperties();
126 switch (properties.deviceType) {
127 case vk::PhysicalDeviceType::eCpu:
128 device_type_score = 1;
129 break;
130 case vk::PhysicalDeviceType::eOther:
131 device_type_score = 1;
132 break;
133 case vk::PhysicalDeviceType::eVirtualGpu:
134 device_type_score = 2;
135 break;
136 case vk::PhysicalDeviceType::eIntegratedGpu:
137 device_type_score = 3;
138 break;
139 case vk::PhysicalDeviceType::eDiscreteGpu:
140 device_type_score = 4;
141 break;
142 }
143 hi_log_info(" - device-type={}, score={}", vk::to_string(properties.deviceType), device_type_score);
144 total_score += device_type_score;
145
146 hi_log_info(" - total score {}", total_score);
147 return total_score;
148}
149
150inline void gfx_device::initialize_device()
151{
152 auto const device_queue_create_infos = make_device_queue_create_infos();
153
154 auto const available_device_features = physicalIntrinsic.getFeatures();
155
156 // Enable optional features.
157 device_features = gfx_system::global().requiredFeatures;
158 device_features.setDualSrcBlend(available_device_features.dualSrcBlend);
159 device_features.setShaderSampledImageArrayDynamicIndexing(VK_TRUE);
160 auto physical_device_features = vk::PhysicalDeviceFeatures2{device_features};
161
162 auto device_descriptor_indexing_features = vk::PhysicalDeviceDescriptorIndexingFeatures{};
163 device_descriptor_indexing_features.setPNext(&physical_device_features);
164 device_descriptor_indexing_features.setShaderSampledImageArrayNonUniformIndexing(VK_TRUE);
165
166 auto device_create_info = vk::DeviceCreateInfo{
167 vk::DeviceCreateFlags(),
168 narrow_cast<uint32_t>(device_queue_create_infos.size()),
169 device_queue_create_infos.data(),
170 0,
171 nullptr,
172 narrow_cast<uint32_t>(requiredExtensions.size()),
173 requiredExtensions.data(),
174 nullptr};
175 device_create_info.setPNext(&device_descriptor_indexing_features);
176
177 intrinsic = physicalIntrinsic.createDevice(device_create_info);
178
179 VmaAllocatorCreateInfo allocatorCreateInfo = {};
180 allocatorCreateInfo.physicalDevice = physicalIntrinsic;
181 allocatorCreateInfo.device = intrinsic;
182 allocatorCreateInfo.instance = vulkan_instance();
183 vmaCreateAllocator(&allocatorCreateInfo, &allocator);
184
185 VmaAllocationCreateInfo lazyAllocationInfo = {};
186 lazyAllocationInfo.flags = VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT;
187 lazyAllocationInfo.pUserData = const_cast<char *>("lazy transient image check");
188 lazyAllocationInfo.usage = VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED;
189 uint32_t typeIndexOut = 0;
190 supportsLazyTransientImages =
191 vmaFindMemoryTypeIndex(allocator, 0, &lazyAllocationInfo, &typeIndexOut) != VK_ERROR_FEATURE_NOT_PRESENT;
192
193 if (supportsLazyTransientImages) {
194 lazyMemoryUsage = VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED;
195 transientImageUsageFlags = vk::ImageUsageFlagBits::eTransientAttachment;
196 }
197
198 initialize_queues(device_queue_create_infos);
199 initialize_quad_index_buffer();
200
201 box_pipeline = std::make_unique<gfx_pipeline_box::device_shared>(*this);
202 image_pipeline = std::make_unique<gfx_pipeline_image::device_shared>(*this);
203 SDF_pipeline = std::make_unique<gfx_pipeline_SDF::device_shared>(*this);
204 override_pipeline = std::make_unique<gfx_pipeline_override::device_shared>(*this);
205 tone_mapper_pipeline = std::make_unique<gfx_pipeline_tone_mapper::device_shared>(*this);
206}
207
208inline void gfx_device::setDebugUtilsObjectNameEXT(vk::DebugUtilsObjectNameInfoEXT const& name_info) const
209{
210#ifndef NDEBUG
211 hi_axiom(gfx_system_mutex.recurse_lock_count());
212 return intrinsic.setDebugUtilsObjectNameEXT(name_info, vulkan_loader());
213#endif
214}
215
216inline void gfx_device::cmdBeginDebugUtilsLabelEXT(vk::CommandBuffer buffer, vk::DebugUtilsLabelEXT const& create_info) const
217{
218#ifndef NDEBUG
219 buffer.beginDebugUtilsLabelEXT(create_info, vulkan_loader());
220#endif
221}
222
223inline void gfx_device::cmdEndDebugUtilsLabelEXT(vk::CommandBuffer buffer) const
224{
225#ifndef NDEBUG
226 buffer.endDebugUtilsLabelEXT(vulkan_loader());
227#endif
228}
229
230} // namespace hi::inline v1
Defines the file class.
STL namespace.
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
unfair_recursive_mutex gfx_system_mutex
Global mutex for GUI elements, like gfx_system, gfx_device, Windows and Widgets.
Definition gfx_system_globals.hpp:18
T move(T... args)