Line data Source code
1 : /**
2 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "XLVkPlatform.h"
24 :
25 : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
26 :
27 : SPUNUSED static VKAPI_ATTR VkBool32 VKAPI_CALL s_debugMessageCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
28 : VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData);
29 :
30 : }
31 :
32 : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk::platform {
33 :
34 : static uint32_t s_InstanceVersion = 0;
35 : static Vector<VkLayerProperties> s_InstanceAvailableLayers;
36 : static Vector<VkExtensionProperties> s_InstanceAvailableExtensions;
37 :
38 42 : Rc<Instance> FunctionTable::createInstance(const Callback<bool(VulkanInstanceData &, const VulkanInstanceInfo &)> &setupCb, Dso &&vulkanModule, Instance::TerminateCallback &&termCb) const {
39 42 : VulkanInstanceInfo info = loadInfo();
40 42 : VulkanInstanceData data;
41 :
42 42 : if (!prepareData(data, info)) {
43 0 : return nullptr;
44 : }
45 :
46 42 : if (!setupCb(data, info)) {
47 0 : log::warn("Vk", "VkInstance creation was aborted by client");
48 0 : return nullptr;
49 : }
50 :
51 42 : if (!validateData(data, info)) {
52 0 : return nullptr;
53 : }
54 :
55 42 : return doCreateInstance(data, move(vulkanModule), move(termCb));
56 42 : }
57 :
58 42 : VulkanInstanceInfo FunctionTable::loadInfo() const {
59 42 : VulkanInstanceInfo ret;
60 :
61 42 : if (s_InstanceVersion == 0) {
62 21 : if (vkEnumerateInstanceVersion) {
63 21 : vkEnumerateInstanceVersion(&s_InstanceVersion);
64 : } else {
65 0 : s_InstanceVersion = VK_API_VERSION_1_0;
66 : }
67 : }
68 :
69 42 : if (s_InstanceAvailableLayers.empty()) {
70 21 : uint32_t layerCount = 0;
71 21 : vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
72 :
73 21 : s_InstanceAvailableLayers.resize(layerCount);
74 21 : vkEnumerateInstanceLayerProperties(&layerCount, s_InstanceAvailableLayers.data());
75 : }
76 :
77 42 : if (s_InstanceAvailableExtensions.empty()) {
78 21 : uint32_t extensionCount = 0;
79 21 : vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
80 :
81 21 : s_InstanceAvailableExtensions.resize(extensionCount);
82 21 : vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, s_InstanceAvailableExtensions.data());
83 : }
84 :
85 42 : ret.targetVersion = s_InstanceVersion;
86 42 : ret.availableLayers = s_InstanceAvailableLayers;
87 42 : ret.availableExtensions = s_InstanceAvailableExtensions;
88 :
89 42 : return ret;
90 : }
91 :
92 42 : bool FunctionTable::prepareData(VulkanInstanceData &data, const VulkanInstanceInfo &info) const {
93 42 : data.targetVulkanVersion = info.targetVersion;
94 :
95 42 : bool layerFound = false;
96 : if constexpr (vk::s_enableValidationLayers) {
97 84 : for (const char *layerName : vk::s_validationLayers) {
98 :
99 420 : for (const auto &layerProperties : s_InstanceAvailableLayers) {
100 420 : if (strcmp(layerName, layerProperties.layerName) == 0) {
101 42 : data.layersToEnable.emplace_back(layerName);
102 42 : layerFound = true;
103 42 : break;
104 : }
105 : }
106 :
107 42 : if (!layerFound) {
108 0 : log::error("Vk", "Validation layer not found: ", layerName);
109 : }
110 : }
111 : }
112 :
113 42 : const char *debugExt = nullptr;
114 :
115 882 : for (auto &extension : s_InstanceAvailableExtensions) {
116 : if constexpr (vk::s_enableValidationLayers) {
117 840 : if (strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, extension.extensionName) == 0) {
118 42 : data.extensionsToEnable.emplace_back(extension.extensionName);
119 42 : debugExt = extension.extensionName;
120 42 : continue;
121 : }
122 : }
123 : }
124 :
125 : if constexpr (vk::s_enableValidationLayers) {
126 42 : if (!debugExt && layerFound) {
127 0 : for (const auto &layerName : vk::s_validationLayers) {
128 : uint32_t layer_ext_count;
129 0 : vkEnumerateInstanceExtensionProperties(layerName, &layer_ext_count, nullptr);
130 0 : if (layer_ext_count == 0) {
131 0 : continue;
132 : }
133 :
134 0 : VkExtensionProperties layer_exts[layer_ext_count];
135 0 : vkEnumerateInstanceExtensionProperties(layerName, &layer_ext_count, layer_exts);
136 :
137 0 : for (auto &extension : layer_exts) {
138 0 : if (strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, extension.extensionName) == 0) {
139 0 : data.extensionsToEnable.emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
140 0 : debugExt = extension.extensionName;
141 0 : break;
142 : }
143 : }
144 :
145 0 : if (debugExt) {
146 0 : break;
147 : }
148 0 : }
149 : }
150 :
151 42 : if (!debugExt) {
152 0 : log::error("Vk", "Required extension not found: ", VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
153 : }
154 : }
155 :
156 42 : return true;
157 : }
158 :
159 42 : bool FunctionTable::validateData(VulkanInstanceData &data, const VulkanInstanceInfo &info) const {
160 42 : bool completeExt = true;
161 84 : for (auto &it : vk::s_requiredExtension) {
162 84 : if (!it) {
163 42 : break;
164 : }
165 :
166 126 : for (auto &extension : data.extensionsToEnable) {
167 84 : if (strcmp(it, extension) == 0) {
168 0 : continue;
169 : }
170 : }
171 :
172 42 : bool found = false;
173 882 : for (auto &extension : info.availableExtensions) {
174 840 : if (strcmp(it, extension.extensionName) == 0) {
175 42 : found = true;
176 42 : data.extensionsToEnable.emplace_back(it);
177 : }
178 : }
179 42 : if (!found) {
180 0 : log::error("Vk", "Required extension not found: ", it);
181 0 : completeExt = false;
182 : }
183 : }
184 :
185 42 : if (!completeExt) {
186 0 : log::error("Vk", "Not all required extensions found, fail to create VkInstance");
187 0 : return false;
188 : }
189 :
190 42 : return true;
191 : }
192 :
193 42 : Rc<Instance> FunctionTable::doCreateInstance(VulkanInstanceData &data, Dso &&vulkanModule, Instance::TerminateCallback &&cb) const {
194 42 : Vector<StringView> enabledOptionals;
195 42 : for (auto &opt : s_optionalExtension) {
196 42 : if (!opt) {
197 42 : break;
198 : }
199 0 : bool found = false;
200 0 : for (auto &it : data.extensionsToEnable) {
201 0 : if (strcmp(it, opt) == 0) {
202 0 : enabledOptionals.emplace_back(StringView(opt));
203 0 : found = true;
204 0 : break;
205 : }
206 : }
207 0 : if (!found) {
208 0 : data.extensionsToEnable.emplace_back(opt);
209 : }
210 : }
211 :
212 42 : const char *debugExt = nullptr;
213 42 : for (auto &it : data.extensionsToEnable) {
214 42 : if (strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, it) == 0) {
215 42 : debugExt = it;
216 42 : break;
217 : }
218 : }
219 :
220 42 : bool validationEnabled = false;
221 84 : for (auto &v : s_validationLayers) {
222 42 : for (auto &it : data.layersToEnable) {
223 42 : if (strcmp(it, v) == 0) {
224 42 : validationEnabled = true;
225 42 : break;
226 : }
227 : }
228 : }
229 :
230 42 : VkInstance instance = VK_NULL_HANDLE;
231 :
232 42 : VkApplicationInfo appInfo{}; vk::sanitizeVkStruct(appInfo);
233 42 : appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
234 42 : appInfo.pNext = nullptr;
235 42 : appInfo.pApplicationName = data.applicationName.data();
236 42 : appInfo.applicationVersion = XL_MAKE_API_VERSION(data.applicationVersion);
237 42 : appInfo.pEngineName = xenolith::platform::name();
238 42 : appInfo.engineVersion = xenolith::platform::version();
239 42 : appInfo.apiVersion = data.targetVulkanVersion;
240 :
241 42 : VkInstanceCreateInfo createInfo{}; vk::sanitizeVkStruct(createInfo);
242 42 : createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
243 42 : createInfo.pNext = nullptr;
244 42 : createInfo.flags = 0;
245 42 : createInfo.pApplicationInfo = &appInfo;
246 :
247 42 : createInfo.enabledExtensionCount = data.extensionsToEnable.size();
248 42 : createInfo.ppEnabledExtensionNames = data.extensionsToEnable.data();
249 :
250 42 : enum VkResult ret = VK_SUCCESS;
251 42 : if (validationEnabled) {
252 42 : VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {};
253 42 : debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
254 42 : debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
255 42 : debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
256 42 : debugCreateInfo.pfnUserCallback = s_debugMessageCallback;
257 42 : createInfo.pNext = &debugCreateInfo;
258 : } else{
259 0 : createInfo.pNext = nullptr;
260 : }
261 :
262 42 : createInfo.enabledLayerCount = data.layersToEnable.size();
263 42 : createInfo.ppEnabledLayerNames = data.layersToEnable.data();
264 42 : ret = vkCreateInstance(&createInfo, nullptr, &instance);
265 :
266 42 : if (ret != VK_SUCCESS) {
267 0 : log::error("Vk", "Fail to create Vulkan instance");
268 0 : return nullptr;
269 : }
270 :
271 42 : auto vkInstance = Rc<vk::Instance>::alloc(instance, vkGetInstanceProcAddr, data.targetVulkanVersion, move(enabledOptionals),
272 84 : move(vulkanModule), move(cb), move(data.checkPresentationSupport), validationEnabled && (debugExt != nullptr), move(data.userdata));
273 :
274 : if constexpr (vk::s_printVkInfo) {
275 42 : StringStream out;
276 42 : out << "\n\tVulkan: " << getVersionDescription(s_InstanceVersion) << "\n\tLayers:\n";
277 462 : for (const auto &layerProperties : s_InstanceAvailableLayers) {
278 420 : out << "\t\t" << layerProperties.layerName << " ("
279 420 : << getVersionDescription(layerProperties.specVersion) << "/"
280 420 : << getVersionDescription(layerProperties.implementationVersion)
281 420 : << ")\t - " << layerProperties.description << "\n";
282 : }
283 :
284 42 : out << "\tExtensions:\n";
285 882 : for (const auto &extension : s_InstanceAvailableExtensions) {
286 840 : out << "\t\t" << extension.extensionName << ": " << getVersionDescription(extension.specVersion) << "\n";
287 : }
288 :
289 42 : vkInstance->printDevicesInfo(out);
290 :
291 42 : log::verbose("Vk-Info", out.str());
292 42 : }
293 :
294 42 : return vkInstance;
295 42 : }
296 :
297 : }
|