1/**************************************************************************/
2/* vulkan_context.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "vulkan_context.h"
32
33#include "core/config/engine.h"
34#include "core/config/project_settings.h"
35#include "core/string/ustring.h"
36#include "core/templates/local_vector.h"
37#include "core/version.h"
38#include "servers/rendering/rendering_device.h"
39
40#include "vk_enum_string_helper.h"
41
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45
46#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
47#define APP_SHORT_NAME "GodotEngine"
48
49VulkanHooks *VulkanContext::vulkan_hooks = nullptr;
50
51Vector<VkAttachmentReference> VulkanContext::_convert_VkAttachmentReference2(uint32_t p_count, const VkAttachmentReference2 *p_refs) {
52 Vector<VkAttachmentReference> att_refs;
53
54 if (p_refs != nullptr) {
55 for (uint32_t i = 0; i < p_count; i++) {
56 // We lose aspectMask in this conversion but we don't use it currently.
57
58 VkAttachmentReference ref = {
59 p_refs[i].attachment, /* attachment */
60 p_refs[i].layout /* layout */
61 };
62
63 att_refs.push_back(ref);
64 }
65 }
66
67 return att_refs;
68}
69
70VkResult VulkanContext::vkCreateRenderPass2KHR(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass) {
71 if (is_device_extension_enabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
72 if (fpCreateRenderPass2KHR == nullptr) {
73 fpCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(p_device, "vkCreateRenderPass2KHR");
74 }
75
76 if (fpCreateRenderPass2KHR == nullptr) {
77 return VK_ERROR_EXTENSION_NOT_PRESENT;
78 } else {
79 return (fpCreateRenderPass2KHR)(p_device, p_create_info, p_allocator, p_render_pass);
80 }
81 } else {
82 // need to fall back on vkCreateRenderPass
83
84 const void *next = p_create_info->pNext; // ATM we only support multiview which should work if supported.
85
86 Vector<VkAttachmentDescription> attachments;
87 for (uint32_t i = 0; i < p_create_info->attachmentCount; i++) {
88 // Basically the old layout just misses type and next.
89 VkAttachmentDescription att = {
90 p_create_info->pAttachments[i].flags, /* flags */
91 p_create_info->pAttachments[i].format, /* format */
92 p_create_info->pAttachments[i].samples, /* samples */
93 p_create_info->pAttachments[i].loadOp, /* loadOp */
94 p_create_info->pAttachments[i].storeOp, /* storeOp */
95 p_create_info->pAttachments[i].stencilLoadOp, /* stencilLoadOp */
96 p_create_info->pAttachments[i].stencilStoreOp, /* stencilStoreOp */
97 p_create_info->pAttachments[i].initialLayout, /* initialLayout */
98 p_create_info->pAttachments[i].finalLayout /* finalLayout */
99 };
100
101 attachments.push_back(att);
102 }
103
104 Vector<Vector<VkAttachmentReference>> attachment_references;
105 Vector<VkSubpassDescription> subpasses;
106 for (uint32_t i = 0; i < p_create_info->subpassCount; i++) {
107 // Here we need to do more, again it's just stripping out type and next
108 // but we have VkAttachmentReference2 to convert to VkAttachmentReference.
109 // Also viewmask is not supported but we don't use it outside of multiview.
110
111 Vector<VkAttachmentReference> input_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].inputAttachmentCount, p_create_info->pSubpasses[i].pInputAttachments);
112 Vector<VkAttachmentReference> color_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pColorAttachments);
113 Vector<VkAttachmentReference> resolve_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pResolveAttachments);
114 Vector<VkAttachmentReference> depth_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pDepthStencilAttachment);
115
116 VkSubpassDescription subpass = {
117 p_create_info->pSubpasses[i].flags, /* flags */
118 p_create_info->pSubpasses[i].pipelineBindPoint, /* pipelineBindPoint */
119 p_create_info->pSubpasses[i].inputAttachmentCount, /* inputAttachmentCount */
120 input_attachments.size() == 0 ? nullptr : input_attachments.ptr(), /* pInputAttachments */
121 p_create_info->pSubpasses[i].colorAttachmentCount, /* colorAttachmentCount */
122 color_attachments.size() == 0 ? nullptr : color_attachments.ptr(), /* pColorAttachments */
123 resolve_attachments.size() == 0 ? nullptr : resolve_attachments.ptr(), /* pResolveAttachments */
124 depth_attachments.size() == 0 ? nullptr : depth_attachments.ptr(), /* pDepthStencilAttachment */
125 p_create_info->pSubpasses[i].preserveAttachmentCount, /* preserveAttachmentCount */
126 p_create_info->pSubpasses[i].pPreserveAttachments /* pPreserveAttachments */
127 };
128 attachment_references.push_back(input_attachments);
129 attachment_references.push_back(color_attachments);
130 attachment_references.push_back(resolve_attachments);
131 attachment_references.push_back(depth_attachments);
132
133 subpasses.push_back(subpass);
134 }
135
136 Vector<VkSubpassDependency> dependencies;
137 for (uint32_t i = 0; i < p_create_info->dependencyCount; i++) {
138 // We lose viewOffset here but again I don't believe we use this anywhere.
139 VkSubpassDependency dep = {
140 p_create_info->pDependencies[i].srcSubpass, /* srcSubpass */
141 p_create_info->pDependencies[i].dstSubpass, /* dstSubpass */
142 p_create_info->pDependencies[i].srcStageMask, /* srcStageMask */
143 p_create_info->pDependencies[i].dstStageMask, /* dstStageMask */
144 p_create_info->pDependencies[i].srcAccessMask, /* srcAccessMask */
145 p_create_info->pDependencies[i].dstAccessMask, /* dstAccessMask */
146 p_create_info->pDependencies[i].dependencyFlags, /* dependencyFlags */
147 };
148
149 dependencies.push_back(dep);
150 }
151
152 // CorrelatedViewMask is not supported in vkCreateRenderPass but we
153 // currently only use this for multiview.
154 // We'll need to look into this.
155
156 VkRenderPassCreateInfo create_info = {
157 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, /* sType */
158 next, /* pNext*/
159 p_create_info->flags, /* flags */
160 (uint32_t)attachments.size(), /* attachmentCount */
161 attachments.ptr(), /* pAttachments */
162 (uint32_t)subpasses.size(), /* subpassCount */
163 subpasses.ptr(), /* pSubpasses */
164 (uint32_t)dependencies.size(), /* */
165 dependencies.ptr(), /* */
166 };
167
168 return vkCreateRenderPass(device, &create_info, p_allocator, p_render_pass);
169 }
170}
171
172VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
173 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
174 VkDebugUtilsMessageTypeFlagsEXT messageType,
175 const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
176 void *pUserData) {
177 // This error needs to be ignored because the AMD allocator will mix up memory types on IGP processors.
178 if (strstr(pCallbackData->pMessage, "Mapping an image with layout") != nullptr &&
179 strstr(pCallbackData->pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr) {
180 return VK_FALSE;
181 }
182 // This needs to be ignored because Validator is wrong here.
183 if (strstr(pCallbackData->pMessage, "Invalid SPIR-V binary version 1.3") != nullptr) {
184 return VK_FALSE;
185 }
186 // This needs to be ignored because Validator is wrong here.
187 if (strstr(pCallbackData->pMessage, "Shader requires flag") != nullptr) {
188 return VK_FALSE;
189 }
190
191 // This needs to be ignored because Validator is wrong here.
192 if (strstr(pCallbackData->pMessage, "SPIR-V module not valid: Pointer operand") != nullptr &&
193 strstr(pCallbackData->pMessage, "must be a memory object") != nullptr) {
194 return VK_FALSE;
195 }
196
197 if (pCallbackData->pMessageIdName && strstr(pCallbackData->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != nullptr) {
198 return VK_FALSE;
199 }
200
201 String type_string;
202 switch (messageType) {
203 case (VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT):
204 type_string = "GENERAL";
205 break;
206 case (VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT):
207 type_string = "VALIDATION";
208 break;
209 case (VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT):
210 type_string = "PERFORMANCE";
211 break;
212 case (VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT):
213 type_string = "VALIDATION|PERFORMANCE";
214 break;
215 }
216
217 String objects_string;
218 if (pCallbackData->objectCount > 0) {
219 objects_string = "\n\tObjects - " + String::num_int64(pCallbackData->objectCount);
220 for (uint32_t object = 0; object < pCallbackData->objectCount; ++object) {
221 objects_string +=
222 "\n\t\tObject[" + String::num_int64(object) + "]" +
223 " - " + string_VkObjectType(pCallbackData->pObjects[object].objectType) +
224 ", Handle " + String::num_int64(pCallbackData->pObjects[object].objectHandle);
225 if (nullptr != pCallbackData->pObjects[object].pObjectName && strlen(pCallbackData->pObjects[object].pObjectName) > 0) {
226 objects_string += ", Name \"" + String(pCallbackData->pObjects[object].pObjectName) + "\"";
227 }
228 }
229 }
230
231 String labels_string;
232 if (pCallbackData->cmdBufLabelCount > 0) {
233 labels_string = "\n\tCommand Buffer Labels - " + String::num_int64(pCallbackData->cmdBufLabelCount);
234 for (uint32_t cmd_buf_label = 0; cmd_buf_label < pCallbackData->cmdBufLabelCount; ++cmd_buf_label) {
235 labels_string +=
236 "\n\t\tLabel[" + String::num_int64(cmd_buf_label) + "]" +
237 " - " + pCallbackData->pCmdBufLabels[cmd_buf_label].pLabelName +
238 "{ ";
239 for (int color_idx = 0; color_idx < 4; ++color_idx) {
240 labels_string += String::num(pCallbackData->pCmdBufLabels[cmd_buf_label].color[color_idx]);
241 if (color_idx < 3) {
242 labels_string += ", ";
243 }
244 }
245 labels_string += " }";
246 }
247 }
248
249 String error_message(type_string +
250 " - Message Id Number: " + String::num_int64(pCallbackData->messageIdNumber) +
251 " | Message Id Name: " + pCallbackData->pMessageIdName +
252 "\n\t" + pCallbackData->pMessage +
253 objects_string + labels_string);
254
255 // Convert VK severity to our own log macros.
256 switch (messageSeverity) {
257 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
258 print_verbose(error_message);
259 break;
260 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
261 print_line(error_message);
262 break;
263 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
264 WARN_PRINT(error_message);
265 break;
266 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
267 ERR_PRINT(error_message);
268 CRASH_COND_MSG(Engine::get_singleton()->is_abort_on_gpu_errors_enabled(),
269 "Crashing, because abort on GPU errors is enabled.");
270 break;
271 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT:
272 break; // Shouldn't happen, only handling to make compilers happy.
273 }
274
275 return VK_FALSE;
276}
277
278VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_report_callback(
279 VkDebugReportFlagsEXT flags,
280 VkDebugReportObjectTypeEXT objectType,
281 uint64_t object,
282 size_t location,
283 int32_t messageCode,
284 const char *pLayerPrefix,
285 const char *pMessage,
286 void *pUserData) {
287 String debugMessage = String("Vulkan Debug Report: object - ") +
288 String::num_int64(object) + "\n" + pMessage;
289
290 switch (flags) {
291 case VK_DEBUG_REPORT_DEBUG_BIT_EXT:
292 case VK_DEBUG_REPORT_INFORMATION_BIT_EXT:
293 print_line(debugMessage);
294 break;
295 case VK_DEBUG_REPORT_WARNING_BIT_EXT:
296 case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT:
297 WARN_PRINT(debugMessage);
298 break;
299 case VK_DEBUG_REPORT_ERROR_BIT_EXT:
300 ERR_PRINT(debugMessage);
301 break;
302 }
303
304 return VK_FALSE;
305}
306
307VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char *const *check_names, uint32_t layer_count, VkLayerProperties *layers) {
308 for (uint32_t i = 0; i < check_count; i++) {
309 VkBool32 found = 0;
310 for (uint32_t j = 0; j < layer_count; j++) {
311 if (!strcmp(check_names[i], layers[j].layerName)) {
312 found = 1;
313 break;
314 }
315 }
316 if (!found) {
317 WARN_PRINT("Can't find layer: " + String(check_names[i]));
318 return 0;
319 }
320 }
321 return 1;
322}
323
324Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const char *const **names) {
325 static const LocalVector<LocalVector<const char *>> instance_validation_layers_alt{
326 // Preferred set of validation layers.
327 { "VK_LAYER_KHRONOS_validation" },
328
329 // Alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers.
330 { "VK_LAYER_LUNARG_standard_validation" },
331
332 // Alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers.
333 { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" }
334 };
335
336 // Clear out-arguments.
337 *count = 0;
338 if (names != nullptr) {
339 *names = nullptr;
340 }
341
342 VkResult err;
343 uint32_t instance_layer_count;
344
345 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, nullptr);
346 if (err) {
347 ERR_FAIL_V(ERR_CANT_CREATE);
348 }
349
350 if (instance_layer_count < 1) {
351 return OK;
352 }
353
354 VkLayerProperties *instance_layers = (VkLayerProperties *)malloc(sizeof(VkLayerProperties) * instance_layer_count);
355 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, instance_layers);
356 if (err) {
357 free(instance_layers);
358 ERR_FAIL_V(ERR_CANT_CREATE);
359 }
360
361 for (const LocalVector<const char *> &layer : instance_validation_layers_alt) {
362 if (_check_layers(layer.size(), layer.ptr(), instance_layer_count, instance_layers)) {
363 *count = layer.size();
364 if (names != nullptr) {
365 *names = layer.ptr();
366 }
367 break;
368 }
369 }
370
371 free(instance_layers);
372
373 return OK;
374}
375
376typedef VkResult(VKAPI_PTR *_vkEnumerateInstanceVersion)(uint32_t *);
377
378Error VulkanContext::_obtain_vulkan_version() {
379 // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html#_description
380 // For Vulkan 1.0 vkEnumerateInstanceVersion is not available, including not in the loader we compile against on Android.
381 _vkEnumerateInstanceVersion func = (_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion");
382 if (func != nullptr) {
383 uint32_t api_version;
384 VkResult res = func(&api_version);
385 if (res == VK_SUCCESS) {
386 instance_api_version = api_version;
387 } else {
388 // According to the documentation this shouldn't fail with anything except a memory allocation error
389 // in which case we're in deep trouble anyway.
390 ERR_FAIL_V(ERR_CANT_CREATE);
391 }
392 } else {
393 print_line("vkEnumerateInstanceVersion not available, assuming Vulkan 1.0.");
394 instance_api_version = VK_API_VERSION_1_0;
395 }
396
397 return OK;
398}
399
400bool VulkanContext::instance_extensions_initialized = false;
401HashMap<CharString, bool> VulkanContext::requested_instance_extensions;
402
403void VulkanContext::register_requested_instance_extension(const CharString &extension_name, bool p_required) {
404 ERR_FAIL_COND_MSG(instance_extensions_initialized, "You can only registered extensions before the Vulkan instance is created");
405 ERR_FAIL_COND(requested_instance_extensions.has(extension_name));
406
407 requested_instance_extensions[extension_name] = p_required;
408}
409
410Error VulkanContext::_initialize_instance_extensions() {
411 enabled_instance_extension_names.clear();
412
413 // Make sure our core extensions are here
414 register_requested_instance_extension(VK_KHR_SURFACE_EXTENSION_NAME, true);
415 register_requested_instance_extension(_get_platform_surface_extension(), true);
416
417 if (_use_validation_layers()) {
418 register_requested_instance_extension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, false);
419 }
420
421 // This extension allows us to use the properties2 features to query additional device capabilities
422 register_requested_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false);
423
424 // Only enable debug utils in verbose mode or DEV_ENABLED.
425 // End users would get spammed with messages of varying verbosity due to the
426 // mess that thirdparty layers/extensions and drivers seem to leave in their
427 // wake, making the Windows registry a bottomless pit of broken layer JSON.
428#ifdef DEV_ENABLED
429 bool want_debug_utils = true;
430#else
431 bool want_debug_utils = OS::get_singleton()->is_stdout_verbose();
432#endif
433 if (want_debug_utils) {
434 register_requested_instance_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, false);
435 }
436
437 // Load instance extensions that are available...
438 uint32_t instance_extension_count = 0;
439 VkResult err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr);
440 ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_INCOMPLETE, ERR_CANT_CREATE);
441 ERR_FAIL_COND_V_MSG(instance_extension_count == 0, ERR_CANT_CREATE, "No instance extensions found, is a driver installed?");
442
443 VkExtensionProperties *instance_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * instance_extension_count);
444 err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions);
445 if (err != VK_SUCCESS && err != VK_INCOMPLETE) {
446 free(instance_extensions);
447 ERR_FAIL_V(ERR_CANT_CREATE);
448 }
449#ifdef DEV_ENABLED
450 for (uint32_t i = 0; i < instance_extension_count; i++) {
451 print_verbose(String("VULKAN: Found instance extension ") + String(instance_extensions[i].extensionName));
452 }
453#endif
454
455 // Enable all extensions that are supported and requested
456 for (uint32_t i = 0; i < instance_extension_count; i++) {
457 CharString extension_name(instance_extensions[i].extensionName);
458 if (requested_instance_extensions.has(extension_name)) {
459 enabled_instance_extension_names.insert(extension_name);
460 }
461 }
462
463 // Now check our requested extensions
464 for (KeyValue<CharString, bool> &requested_extension : requested_instance_extensions) {
465 if (!enabled_instance_extension_names.has(requested_extension.key)) {
466 if (requested_extension.value) {
467 free(instance_extensions);
468 ERR_FAIL_V_MSG(ERR_BUG, String("Required extension ") + String(requested_extension.key) + String(" not found, is a driver installed?"));
469 } else {
470 print_verbose(String("Optional extension ") + String(requested_extension.key) + String(" not found"));
471 }
472 }
473 }
474
475 free(instance_extensions);
476
477 instance_extensions_initialized = true;
478 return OK;
479}
480
481bool VulkanContext::device_extensions_initialized = false;
482HashMap<CharString, bool> VulkanContext::requested_device_extensions;
483
484void VulkanContext::register_requested_device_extension(const CharString &extension_name, bool p_required) {
485 ERR_FAIL_COND_MSG(device_extensions_initialized, "You can only registered extensions before the Vulkan instance is created");
486 ERR_FAIL_COND(requested_device_extensions.has(extension_name));
487
488 requested_device_extensions[extension_name] = p_required;
489}
490
491Error VulkanContext::_initialize_device_extensions() {
492 // Look for device extensions.
493 enabled_device_extension_names.clear();
494
495 // Make sure our core extensions are here
496 register_requested_device_extension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true);
497
498 register_requested_device_extension(VK_KHR_MULTIVIEW_EXTENSION_NAME, false);
499 register_requested_device_extension(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, false);
500 register_requested_device_extension(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, false);
501 register_requested_device_extension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
502 register_requested_device_extension(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, false);
503 register_requested_device_extension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, false);
504 register_requested_device_extension(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, false);
505 register_requested_device_extension(VK_KHR_MAINTENANCE_2_EXTENSION_NAME, false);
506 register_requested_device_extension(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME, false);
507
508 if (Engine::get_singleton()->is_generate_spirv_debug_info_enabled()) {
509 register_requested_device_extension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, true);
510 }
511
512 // TODO consider the following extensions:
513 // - VK_KHR_spirv_1_4
514 // - VK_KHR_swapchain_mutable_format
515 // - VK_EXT_full_screen_exclusive
516 // - VK_EXT_hdr_metadata
517 // - VK_KHR_depth_stencil_resolve
518
519 // Even though the user "enabled" the extension via the command
520 // line, we must make sure that it's enumerated for use with the
521 // device. Therefore, disable it here, and re-enable it again if
522 // enumerated.
523 if (VK_KHR_incremental_present_enabled) {
524 register_requested_device_extension(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, false);
525 }
526 if (VK_GOOGLE_display_timing_enabled) {
527 register_requested_device_extension(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, false);
528 }
529
530 // obtain available device extensions
531 uint32_t device_extension_count = 0;
532 VkResult err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, nullptr);
533 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
534 ERR_FAIL_COND_V_MSG(device_extension_count == 0, ERR_CANT_CREATE,
535 "vkEnumerateDeviceExtensionProperties failed to find any extensions\n\n"
536 "Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
537 "vkCreateInstance Failure");
538
539 VkExtensionProperties *device_extensions = (VkExtensionProperties *)malloc(sizeof(VkExtensionProperties) * device_extension_count);
540 err = vkEnumerateDeviceExtensionProperties(gpu, nullptr, &device_extension_count, device_extensions);
541 if (err) {
542 free(device_extensions);
543 ERR_FAIL_V(ERR_CANT_CREATE);
544 }
545
546#ifdef DEV_ENABLED
547 for (uint32_t i = 0; i < device_extension_count; i++) {
548 print_verbose(String("VULKAN: Found device extension ") + String(device_extensions[i].extensionName));
549 }
550#endif
551
552 // Enable all extensions that are supported and requested
553 for (uint32_t i = 0; i < device_extension_count; i++) {
554 CharString extension_name(device_extensions[i].extensionName);
555 if (requested_device_extensions.has(extension_name)) {
556 enabled_device_extension_names.insert(extension_name);
557 }
558 }
559
560 // Now check our requested extensions
561 for (KeyValue<CharString, bool> &requested_extension : requested_device_extensions) {
562 if (!enabled_device_extension_names.has(requested_extension.key)) {
563 if (requested_extension.value) {
564 free(device_extensions);
565 ERR_FAIL_V_MSG(ERR_BUG,
566 String("vkEnumerateDeviceExtensionProperties failed to find the ") + String(requested_extension.key) + String(" extension.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\nvkCreateInstance Failure"));
567 } else {
568 print_verbose(String("Optional extension ") + String(requested_extension.key) + String(" not found"));
569 }
570 }
571 }
572
573 free(device_extensions);
574
575 device_extensions_initialized = true;
576 return OK;
577}
578
579uint32_t VulkanContext::SubgroupCapabilities::supported_stages_flags_rd() const {
580 uint32_t flags = 0;
581
582 if (supportedStages & VK_SHADER_STAGE_VERTEX_BIT) {
583 flags += RenderingDevice::ShaderStage::SHADER_STAGE_VERTEX_BIT;
584 }
585 if (supportedStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
586 flags += RenderingDevice::ShaderStage::SHADER_STAGE_TESSELATION_CONTROL_BIT;
587 }
588 if (supportedStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
589 flags += RenderingDevice::ShaderStage::SHADER_STAGE_TESSELATION_EVALUATION_BIT;
590 }
591 // if (supportedStages & VK_SHADER_STAGE_GEOMETRY_BIT) {
592 // flags += RenderingDevice::ShaderStage::SHADER_STAGE_GEOMETRY_BIT;
593 // }
594 if (supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) {
595 flags += RenderingDevice::ShaderStage::SHADER_STAGE_FRAGMENT_BIT;
596 }
597 if (supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) {
598 flags += RenderingDevice::ShaderStage::SHADER_STAGE_COMPUTE_BIT;
599 }
600
601 return flags;
602}
603
604String VulkanContext::SubgroupCapabilities::supported_stages_desc() const {
605 String res;
606
607 if (supportedStages & VK_SHADER_STAGE_VERTEX_BIT) {
608 res += ", STAGE_VERTEX";
609 }
610 if (supportedStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
611 res += ", STAGE_TESSELLATION_CONTROL";
612 }
613 if (supportedStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
614 res += ", STAGE_TESSELLATION_EVALUATION";
615 }
616 if (supportedStages & VK_SHADER_STAGE_GEOMETRY_BIT) {
617 res += ", STAGE_GEOMETRY";
618 }
619 if (supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) {
620 res += ", STAGE_FRAGMENT";
621 }
622 if (supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) {
623 res += ", STAGE_COMPUTE";
624 }
625
626 // These are not defined on Android GRMBL.
627 if (supportedStages & 0x00000100 /* VK_SHADER_STAGE_RAYGEN_BIT_KHR */) {
628 res += ", STAGE_RAYGEN_KHR";
629 }
630 if (supportedStages & 0x00000200 /* VK_SHADER_STAGE_ANY_HIT_BIT_KHR */) {
631 res += ", STAGE_ANY_HIT_KHR";
632 }
633 if (supportedStages & 0x00000400 /* VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR */) {
634 res += ", STAGE_CLOSEST_HIT_KHR";
635 }
636 if (supportedStages & 0x00000800 /* VK_SHADER_STAGE_MISS_BIT_KHR */) {
637 res += ", STAGE_MISS_KHR";
638 }
639 if (supportedStages & 0x00001000 /* VK_SHADER_STAGE_INTERSECTION_BIT_KHR */) {
640 res += ", STAGE_INTERSECTION_KHR";
641 }
642 if (supportedStages & 0x00002000 /* VK_SHADER_STAGE_CALLABLE_BIT_KHR */) {
643 res += ", STAGE_CALLABLE_KHR";
644 }
645 if (supportedStages & 0x00000040 /* VK_SHADER_STAGE_TASK_BIT_NV */) {
646 res += ", STAGE_TASK_NV";
647 }
648 if (supportedStages & 0x00000080 /* VK_SHADER_STAGE_MESH_BIT_NV */) {
649 res += ", STAGE_MESH_NV";
650 }
651
652 return res.substr(2); // Remove first ", ".
653}
654
655uint32_t VulkanContext::SubgroupCapabilities::supported_operations_flags_rd() const {
656 uint32_t flags = 0;
657
658 if (supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) {
659 flags += RenderingDevice::SubgroupOperations::SUBGROUP_BASIC_BIT;
660 }
661 if (supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT) {
662 flags += RenderingDevice::SubgroupOperations::SUBGROUP_VOTE_BIT;
663 }
664 if (supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) {
665 flags += RenderingDevice::SubgroupOperations::SUBGROUP_ARITHMETIC_BIT;
666 }
667 if (supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) {
668 flags += RenderingDevice::SubgroupOperations::SUBGROUP_BALLOT_BIT;
669 }
670 if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) {
671 flags += RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_BIT;
672 }
673 if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) {
674 flags += RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_RELATIVE_BIT;
675 }
676 if (supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) {
677 flags += RenderingDevice::SubgroupOperations::SUBGROUP_CLUSTERED_BIT;
678 }
679 if (supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT) {
680 flags += RenderingDevice::SubgroupOperations::SUBGROUP_QUAD_BIT;
681 }
682
683 return flags;
684}
685
686String VulkanContext::SubgroupCapabilities::supported_operations_desc() const {
687 String res;
688
689 if (supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) {
690 res += ", FEATURE_BASIC";
691 }
692 if (supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT) {
693 res += ", FEATURE_VOTE";
694 }
695 if (supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) {
696 res += ", FEATURE_ARITHMETIC";
697 }
698 if (supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) {
699 res += ", FEATURE_BALLOT";
700 }
701 if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) {
702 res += ", FEATURE_SHUFFLE";
703 }
704 if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) {
705 res += ", FEATURE_SHUFFLE_RELATIVE";
706 }
707 if (supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) {
708 res += ", FEATURE_CLUSTERED";
709 }
710 if (supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT) {
711 res += ", FEATURE_QUAD";
712 }
713 if (supportedOperations & VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV) {
714 res += ", FEATURE_PARTITIONED_NV";
715 }
716
717 return res.substr(2); // Remove first ", ".
718}
719
720Error VulkanContext::_check_capabilities() {
721 // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_multiview.html
722 // https://www.khronos.org/blog/vulkan-subgroup-tutorial
723
724 // For Vulkan 1.0 vkGetPhysicalDeviceProperties2 is not available, including not in the loader we compile against on Android.
725
726 // So we check if the functions are accessible by getting their function pointers and skipping if not
727 // (note that the desktop loader does a better job here but the android loader doesn't.)
728
729 // Assume not supported until proven otherwise.
730 vrs_capabilities.pipeline_vrs_supported = false;
731 vrs_capabilities.primitive_vrs_supported = false;
732 vrs_capabilities.attachment_vrs_supported = false;
733 vrs_capabilities.min_texel_size = Size2i();
734 vrs_capabilities.max_texel_size = Size2i();
735 vrs_capabilities.texel_size = Size2i();
736 multiview_capabilities.is_supported = false;
737 multiview_capabilities.geometry_shader_is_supported = false;
738 multiview_capabilities.tessellation_shader_is_supported = false;
739 multiview_capabilities.max_view_count = 0;
740 multiview_capabilities.max_instance_count = 0;
741 subgroup_capabilities.size = 0;
742 subgroup_capabilities.supportedStages = 0;
743 subgroup_capabilities.supportedOperations = 0;
744 subgroup_capabilities.quadOperationsInAllStages = false;
745 shader_capabilities.shader_float16_is_supported = false;
746 shader_capabilities.shader_int8_is_supported = false;
747 storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = false;
748 storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = false;
749 storage_buffer_capabilities.storage_push_constant_16_is_supported = false;
750 storage_buffer_capabilities.storage_input_output_16 = false;
751
752 if (is_instance_extension_enabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
753 // Check for extended features.
754 PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2");
755 if (vkGetPhysicalDeviceFeatures2_func == nullptr) {
756 // In Vulkan 1.0 might be accessible under its original extension name.
757 vkGetPhysicalDeviceFeatures2_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR");
758 }
759 if (vkGetPhysicalDeviceFeatures2_func != nullptr) {
760 // Check our extended features.
761 void *next = nullptr;
762
763 // We must check that the relative extension is present before assuming a
764 // feature as enabled.
765 // See also: https://github.com/godotengine/godot/issues/65409
766
767 VkPhysicalDeviceVulkan12Features device_features_vk12 = {};
768 VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = {};
769 VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = {};
770 VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {};
771 VkPhysicalDeviceMultiviewFeatures multiview_features = {};
772
773 if (device_api_version >= VK_API_VERSION_1_2) {
774 device_features_vk12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
775 device_features_vk12.pNext = next;
776 next = &device_features_vk12;
777 } else {
778 if (is_device_extension_enabled(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) {
779 shader_features = {
780 /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR,
781 /*pNext*/ next,
782 /*shaderFloat16*/ false,
783 /*shaderInt8*/ false,
784 };
785 next = &shader_features;
786 }
787 }
788
789 if (is_device_extension_enabled(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) {
790 vrs_features = {
791 /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR,
792 /*pNext*/ next,
793 /*pipelineFragmentShadingRate*/ false,
794 /*primitiveFragmentShadingRate*/ false,
795 /*attachmentFragmentShadingRate*/ false,
796 };
797 next = &vrs_features;
798 }
799
800 if (is_device_extension_enabled(VK_KHR_16BIT_STORAGE_EXTENSION_NAME)) {
801 storage_feature = {
802 /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,
803 /*pNext*/ next,
804 /*storageBuffer16BitAccess*/ false,
805 /*uniformAndStorageBuffer16BitAccess*/ false,
806 /*storagePushConstant16*/ false,
807 /*storageInputOutput16*/ false,
808 };
809 next = &storage_feature;
810 }
811
812 if (is_device_extension_enabled(VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
813 multiview_features = {
814 /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
815 /*pNext*/ next,
816 /*multiview*/ false,
817 /*multiviewGeometryShader*/ false,
818 /*multiviewTessellationShader*/ false,
819 };
820 next = &multiview_features;
821 }
822
823 VkPhysicalDeviceFeatures2 device_features;
824 device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
825 device_features.pNext = next;
826
827 vkGetPhysicalDeviceFeatures2_func(gpu, &device_features);
828
829 if (device_api_version >= VK_API_VERSION_1_2) {
830#ifdef MACOS_ENABLED
831 ERR_FAIL_COND_V_MSG(!device_features_vk12.shaderSampledImageArrayNonUniformIndexing, ERR_CANT_CREATE, "Your GPU doesn't support shaderSampledImageArrayNonUniformIndexing which is required to use the Vulkan-based renderers in Godot.");
832#endif
833
834 if (is_device_extension_enabled(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) {
835 shader_capabilities.shader_float16_is_supported = device_features_vk12.shaderFloat16;
836 shader_capabilities.shader_int8_is_supported = device_features_vk12.shaderInt8;
837 }
838 } else {
839 if (is_device_extension_enabled(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)) {
840 shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16;
841 shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8;
842 }
843 }
844
845 if (is_device_extension_enabled(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME)) {
846 vrs_capabilities.pipeline_vrs_supported = vrs_features.pipelineFragmentShadingRate;
847 vrs_capabilities.primitive_vrs_supported = vrs_features.primitiveFragmentShadingRate;
848 vrs_capabilities.attachment_vrs_supported = vrs_features.attachmentFragmentShadingRate;
849 }
850
851 if (is_device_extension_enabled(VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
852 multiview_capabilities.is_supported = multiview_features.multiview;
853 multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader;
854 multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader;
855 }
856
857 if (is_device_extension_enabled(VK_KHR_16BIT_STORAGE_EXTENSION_NAME)) {
858 storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = storage_feature.storageBuffer16BitAccess;
859 storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = storage_feature.uniformAndStorageBuffer16BitAccess;
860 storage_buffer_capabilities.storage_push_constant_16_is_supported = storage_feature.storagePushConstant16;
861 storage_buffer_capabilities.storage_input_output_16 = storage_feature.storageInputOutput16;
862 }
863 }
864
865 // Check extended properties.
866 PFN_vkGetPhysicalDeviceProperties2 device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2");
867 if (device_properties_func == nullptr) {
868 // In Vulkan 1.0 might be accessible under its original extension name.
869 device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2KHR");
870 }
871 if (device_properties_func != nullptr) {
872 VkPhysicalDeviceFragmentShadingRatePropertiesKHR vrsProperties{};
873 VkPhysicalDeviceMultiviewProperties multiviewProperties{};
874 VkPhysicalDeviceSubgroupProperties subgroupProperties{};
875 VkPhysicalDeviceProperties2 physicalDeviceProperties{};
876 void *nextptr = nullptr;
877
878 if (device_api_version >= VK_API_VERSION_1_1) { // Vulkan 1.1 or higher
879 subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
880 subgroupProperties.pNext = nextptr;
881
882 nextptr = &subgroupProperties;
883 }
884
885 if (multiview_capabilities.is_supported) {
886 multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
887 multiviewProperties.pNext = nextptr;
888
889 nextptr = &multiviewProperties;
890 }
891
892 if (vrs_capabilities.attachment_vrs_supported) {
893 vrsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
894 vrsProperties.pNext = nextptr;
895
896 nextptr = &vrsProperties;
897 }
898
899 physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
900 physicalDeviceProperties.pNext = nextptr;
901
902 device_properties_func(gpu, &physicalDeviceProperties);
903
904 subgroup_capabilities.size = subgroupProperties.subgroupSize;
905 subgroup_capabilities.supportedStages = subgroupProperties.supportedStages;
906 subgroup_capabilities.supportedOperations = subgroupProperties.supportedOperations;
907 // Note: quadOperationsInAllStages will be true if:
908 // - supportedStages has VK_SHADER_STAGE_ALL_GRAPHICS + VK_SHADER_STAGE_COMPUTE_BIT.
909 // - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT.
910 subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages;
911
912 if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) {
913 print_verbose("- Vulkan Variable Rate Shading supported:");
914 if (vrs_capabilities.pipeline_vrs_supported) {
915 print_verbose(" Pipeline fragment shading rate");
916 }
917 if (vrs_capabilities.primitive_vrs_supported) {
918 print_verbose(" Primitive fragment shading rate");
919 }
920 if (vrs_capabilities.attachment_vrs_supported) {
921 // TODO expose these somehow to the end user.
922 vrs_capabilities.min_texel_size.x = vrsProperties.minFragmentShadingRateAttachmentTexelSize.width;
923 vrs_capabilities.min_texel_size.y = vrsProperties.minFragmentShadingRateAttachmentTexelSize.height;
924 vrs_capabilities.max_texel_size.x = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.width;
925 vrs_capabilities.max_texel_size.y = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.height;
926
927 // We'll attempt to default to a texel size of 16x16
928 vrs_capabilities.texel_size.x = CLAMP(16, vrs_capabilities.min_texel_size.x, vrs_capabilities.max_texel_size.x);
929 vrs_capabilities.texel_size.y = CLAMP(16, vrs_capabilities.min_texel_size.y, vrs_capabilities.max_texel_size.y);
930
931 print_verbose(String(" Attachment fragment shading rate") + String(", min texel size: (") + itos(vrs_capabilities.min_texel_size.x) + String(", ") + itos(vrs_capabilities.min_texel_size.y) + String(")") + String(", max texel size: (") + itos(vrs_capabilities.max_texel_size.x) + String(", ") + itos(vrs_capabilities.max_texel_size.y) + String(")"));
932 }
933
934 } else {
935 print_verbose("- Vulkan Variable Rate Shading not supported");
936 }
937
938 if (multiview_capabilities.is_supported) {
939 multiview_capabilities.max_view_count = multiviewProperties.maxMultiviewViewCount;
940 multiview_capabilities.max_instance_count = multiviewProperties.maxMultiviewInstanceIndex;
941
942 print_verbose("- Vulkan multiview supported:");
943 print_verbose(" max view count: " + itos(multiview_capabilities.max_view_count));
944 print_verbose(" max instances: " + itos(multiview_capabilities.max_instance_count));
945 } else {
946 print_verbose("- Vulkan multiview not supported");
947 }
948
949 print_verbose("- Vulkan subgroup:");
950 print_verbose(" size: " + itos(subgroup_capabilities.size));
951 print_verbose(" stages: " + subgroup_capabilities.supported_stages_desc());
952 print_verbose(" supported ops: " + subgroup_capabilities.supported_operations_desc());
953 if (subgroup_capabilities.quadOperationsInAllStages) {
954 print_verbose(" quad operations in all stages");
955 }
956 } else {
957 print_verbose("- Couldn't call vkGetPhysicalDeviceProperties2");
958 }
959 }
960
961 return OK;
962}
963
964Error VulkanContext::_create_instance() {
965 // Obtain Vulkan version.
966 _obtain_vulkan_version();
967
968 // Initialize extensions.
969 {
970 Error err = _initialize_instance_extensions();
971 if (err != OK) {
972 return err;
973 }
974 }
975
976 int enabled_extension_count = 0;
977 const char *enabled_extension_names[MAX_EXTENSIONS];
978 ERR_FAIL_COND_V(enabled_instance_extension_names.size() > MAX_EXTENSIONS, ERR_CANT_CREATE);
979 for (const CharString &extension_name : enabled_instance_extension_names) {
980 enabled_extension_names[enabled_extension_count++] = extension_name.ptr();
981 }
982
983 // We'll set application version to the Vulkan version we're developing against, even if our instance is based on
984 // an older Vulkan version, devices can still support newer versions of Vulkan.
985 // The exception is when we're on Vulkan 1.0, we should not set this to anything but 1.0.
986 // Note that this value is only used by validation layers to warn us about version issues.
987 uint32_t application_api_version = instance_api_version == VK_API_VERSION_1_0 ? VK_API_VERSION_1_0 : VK_API_VERSION_1_2;
988
989 CharString cs = GLOBAL_GET("application/config/name").operator String().utf8();
990 const VkApplicationInfo app = {
991 /*sType*/ VK_STRUCTURE_TYPE_APPLICATION_INFO,
992 /*pNext*/ nullptr,
993 /*pApplicationName*/ cs.get_data(),
994 /*applicationVersion*/ 0, // It would be really nice if we store a version number in project settings, say "application/config/version"
995 /*pEngineName*/ VERSION_NAME,
996 /*engineVersion*/ VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH),
997 /*apiVersion*/ application_api_version
998 };
999 VkInstanceCreateInfo inst_info{};
1000 inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
1001 inst_info.pApplicationInfo = &app;
1002 inst_info.enabledExtensionCount = enabled_extension_count;
1003 inst_info.ppEnabledExtensionNames = (const char *const *)enabled_extension_names;
1004 if (_use_validation_layers()) {
1005 _get_preferred_validation_layers(&inst_info.enabledLayerCount, &inst_info.ppEnabledLayerNames);
1006 }
1007
1008 /*
1009 * This is info for a temp callback to use during CreateInstance.
1010 * After the instance is created, we use the instance-based
1011 * function to register the final callback.
1012 */
1013 VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info = {};
1014 VkDebugReportCallbackCreateInfoEXT dbg_report_callback_create_info = {};
1015 if (is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
1016 // VK_EXT_debug_utils style.
1017 dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
1018 dbg_messenger_create_info.pNext = nullptr;
1019 dbg_messenger_create_info.flags = 0;
1020 dbg_messenger_create_info.messageSeverity =
1021 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
1022 dbg_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
1023 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
1024 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
1025 dbg_messenger_create_info.pfnUserCallback = _debug_messenger_callback;
1026 dbg_messenger_create_info.pUserData = this;
1027 inst_info.pNext = &dbg_messenger_create_info;
1028 } else if (is_instance_extension_enabled(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
1029 dbg_report_callback_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
1030 dbg_report_callback_create_info.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
1031 VK_DEBUG_REPORT_WARNING_BIT_EXT |
1032 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
1033 VK_DEBUG_REPORT_ERROR_BIT_EXT |
1034 VK_DEBUG_REPORT_DEBUG_BIT_EXT;
1035 dbg_report_callback_create_info.pfnCallback = _debug_report_callback;
1036 dbg_report_callback_create_info.pUserData = this;
1037 inst_info.pNext = &dbg_report_callback_create_info;
1038 }
1039
1040 VkResult err;
1041
1042 if (vulkan_hooks) {
1043 if (!vulkan_hooks->create_vulkan_instance(&inst_info, &inst)) {
1044 return ERR_CANT_CREATE;
1045 }
1046 } else {
1047 err = vkCreateInstance(&inst_info, nullptr, &inst);
1048 ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE,
1049 "Cannot find a compatible Vulkan installable client driver (ICD).\n\n"
1050 "vkCreateInstance Failure");
1051 ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE,
1052 "Cannot find a specified extension library.\n"
1053 "Make sure your layers path is set appropriately.\n"
1054 "vkCreateInstance Failure");
1055 ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE,
1056 "vkCreateInstance failed.\n\n"
1057 "Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
1058 "Please look at the Getting Started guide for additional information.\n"
1059 "vkCreateInstance Failure");
1060 }
1061
1062 inst_initialized = true;
1063
1064#ifdef USE_VOLK
1065 volkLoadInstance(inst);
1066#endif
1067
1068 if (is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
1069 // Setup VK_EXT_debug_utils function pointers always (we use them for debug labels and names).
1070 CreateDebugUtilsMessengerEXT =
1071 (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugUtilsMessengerEXT");
1072 DestroyDebugUtilsMessengerEXT =
1073 (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugUtilsMessengerEXT");
1074 SubmitDebugUtilsMessageEXT =
1075 (PFN_vkSubmitDebugUtilsMessageEXT)vkGetInstanceProcAddr(inst, "vkSubmitDebugUtilsMessageEXT");
1076 CmdBeginDebugUtilsLabelEXT =
1077 (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdBeginDebugUtilsLabelEXT");
1078 CmdEndDebugUtilsLabelEXT =
1079 (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdEndDebugUtilsLabelEXT");
1080 CmdInsertDebugUtilsLabelEXT =
1081 (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(inst, "vkCmdInsertDebugUtilsLabelEXT");
1082 SetDebugUtilsObjectNameEXT =
1083 (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(inst, "vkSetDebugUtilsObjectNameEXT");
1084 if (nullptr == CreateDebugUtilsMessengerEXT || nullptr == DestroyDebugUtilsMessengerEXT ||
1085 nullptr == SubmitDebugUtilsMessageEXT || nullptr == CmdBeginDebugUtilsLabelEXT ||
1086 nullptr == CmdEndDebugUtilsLabelEXT || nullptr == CmdInsertDebugUtilsLabelEXT ||
1087 nullptr == SetDebugUtilsObjectNameEXT) {
1088 ERR_FAIL_V_MSG(ERR_CANT_CREATE,
1089 "GetProcAddr: Failed to init VK_EXT_debug_utils\n"
1090 "GetProcAddr: Failure");
1091 }
1092
1093 err = CreateDebugUtilsMessengerEXT(inst, &dbg_messenger_create_info, nullptr, &dbg_messenger);
1094 switch (err) {
1095 case VK_SUCCESS:
1096 break;
1097 case VK_ERROR_OUT_OF_HOST_MEMORY:
1098 ERR_FAIL_V_MSG(ERR_CANT_CREATE,
1099 "CreateDebugUtilsMessengerEXT: out of host memory\n"
1100 "CreateDebugUtilsMessengerEXT Failure");
1101 break;
1102 default:
1103 ERR_FAIL_V_MSG(ERR_CANT_CREATE,
1104 "CreateDebugUtilsMessengerEXT: unknown failure\n"
1105 "CreateDebugUtilsMessengerEXT Failure");
1106 ERR_FAIL_V(ERR_CANT_CREATE);
1107 break;
1108 }
1109 } else if (is_instance_extension_enabled(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
1110 CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugReportCallbackEXT");
1111 DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(inst, "vkDebugReportMessageEXT");
1112 DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugReportCallbackEXT");
1113
1114 if (nullptr == CreateDebugReportCallbackEXT || nullptr == DebugReportMessageEXT || nullptr == DestroyDebugReportCallbackEXT) {
1115 ERR_FAIL_V_MSG(ERR_CANT_CREATE,
1116 "GetProcAddr: Failed to init VK_EXT_debug_report\n"
1117 "GetProcAddr: Failure");
1118 }
1119
1120 err = CreateDebugReportCallbackEXT(inst, &dbg_report_callback_create_info, nullptr, &dbg_debug_report);
1121 switch (err) {
1122 case VK_SUCCESS:
1123 break;
1124 case VK_ERROR_OUT_OF_HOST_MEMORY:
1125 ERR_FAIL_V_MSG(ERR_CANT_CREATE,
1126 "CreateDebugReportCallbackEXT: out of host memory\n"
1127 "CreateDebugReportCallbackEXT Failure");
1128 break;
1129 default:
1130 ERR_FAIL_V_MSG(ERR_CANT_CREATE,
1131 "CreateDebugReportCallbackEXT: unknown failure\n"
1132 "CreateDebugReportCallbackEXT Failure");
1133 ERR_FAIL_V(ERR_CANT_CREATE);
1134 break;
1135 }
1136 }
1137
1138 return OK;
1139}
1140
1141Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
1142 // Make initial call to query gpu_count, then second call for gpu info.
1143 uint32_t gpu_count = 0;
1144 VkResult err = vkEnumeratePhysicalDevices(inst, &gpu_count, nullptr);
1145 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
1146 ERR_FAIL_COND_V_MSG(gpu_count == 0, ERR_CANT_CREATE,
1147 "vkEnumeratePhysicalDevices reported zero accessible devices.\n\n"
1148 "Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
1149 "vkEnumeratePhysicalDevices Failure");
1150
1151 VkPhysicalDevice *physical_devices = (VkPhysicalDevice *)malloc(sizeof(VkPhysicalDevice) * gpu_count);
1152 err = vkEnumeratePhysicalDevices(inst, &gpu_count, physical_devices);
1153 if (err) {
1154 free(physical_devices);
1155 ERR_FAIL_V(ERR_CANT_CREATE);
1156 }
1157
1158 static const struct {
1159 uint32_t id;
1160 const char *name;
1161 } vendor_names[] = {
1162 { 0x1002, "AMD" },
1163 { 0x1010, "ImgTec" },
1164 { 0x106B, "Apple" },
1165 { 0x10DE, "NVIDIA" },
1166 { 0x13B5, "ARM" },
1167 { 0x5143, "Qualcomm" },
1168 { 0x8086, "Intel" },
1169 { 0, nullptr },
1170 };
1171
1172 int32_t device_index = -1;
1173 if (vulkan_hooks) {
1174 if (!vulkan_hooks->get_physical_device(&gpu)) {
1175 return ERR_CANT_CREATE;
1176 }
1177
1178 // Not really needed but nice to print the correct entry.
1179 for (uint32_t i = 0; i < gpu_count; ++i) {
1180 if (physical_devices[i] == gpu) {
1181 device_index = i;
1182 break;
1183 }
1184 }
1185 } else {
1186 // TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances.
1187 // The device should really be a preference, but for now choosing a discrete GPU over the
1188 // integrated one is better than the default.
1189
1190 int type_selected = -1;
1191 print_verbose("Vulkan devices:");
1192 for (uint32_t i = 0; i < gpu_count; ++i) {
1193 VkPhysicalDeviceProperties props;
1194 vkGetPhysicalDeviceProperties(physical_devices[i], &props);
1195
1196 bool present_supported = false;
1197
1198 uint32_t device_queue_family_count = 0;
1199 vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, nullptr);
1200 VkQueueFamilyProperties *device_queue_props = (VkQueueFamilyProperties *)malloc(device_queue_family_count * sizeof(VkQueueFamilyProperties));
1201 vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, device_queue_props);
1202 for (uint32_t j = 0; j < device_queue_family_count; j++) {
1203 if ((device_queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
1204 VkBool32 supports;
1205 err = vkGetPhysicalDeviceSurfaceSupportKHR(
1206 physical_devices[i], j, p_surface, &supports);
1207 if (err == VK_SUCCESS && supports) {
1208 present_supported = true;
1209 } else {
1210 continue;
1211 }
1212 }
1213 }
1214 String name = props.deviceName;
1215 String vendor = "Unknown";
1216 String dev_type;
1217 switch (props.deviceType) {
1218 case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: {
1219 dev_type = "Discrete";
1220 } break;
1221 case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: {
1222 dev_type = "Integrated";
1223 } break;
1224 case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: {
1225 dev_type = "Virtual";
1226 } break;
1227 case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: {
1228 dev_type = "CPU";
1229 } break;
1230 default: {
1231 dev_type = "Other";
1232 } break;
1233 }
1234 uint32_t vendor_idx = 0;
1235 while (vendor_names[vendor_idx].name != nullptr) {
1236 if (props.vendorID == vendor_names[vendor_idx].id) {
1237 vendor = vendor_names[vendor_idx].name;
1238 break;
1239 }
1240 vendor_idx++;
1241 }
1242 free(device_queue_props);
1243 print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + dev_type);
1244
1245 if (present_supported) { // Select first supported device of preferred type: Discrete > Integrated > Virtual > CPU > Other.
1246 switch (props.deviceType) {
1247 case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: {
1248 if (type_selected < 4) {
1249 type_selected = 4;
1250 device_index = i;
1251 }
1252 } break;
1253 case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: {
1254 if (type_selected < 3) {
1255 type_selected = 3;
1256 device_index = i;
1257 }
1258 } break;
1259 case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: {
1260 if (type_selected < 2) {
1261 type_selected = 2;
1262 device_index = i;
1263 }
1264 } break;
1265 case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: {
1266 if (type_selected < 1) {
1267 type_selected = 1;
1268 device_index = i;
1269 }
1270 } break;
1271 default: {
1272 if (type_selected < 0) {
1273 type_selected = 0;
1274 device_index = i;
1275 }
1276 } break;
1277 }
1278 }
1279 }
1280
1281 int32_t user_device_index = Engine::get_singleton()->get_gpu_index(); // Force user selected GPU.
1282 if (user_device_index >= 0 && user_device_index < (int32_t)gpu_count) {
1283 device_index = user_device_index;
1284 }
1285
1286 ERR_FAIL_COND_V_MSG(device_index == -1, ERR_CANT_CREATE, "None of Vulkan devices supports both graphics and present queues.");
1287
1288 gpu = physical_devices[device_index];
1289 }
1290
1291 free(physical_devices);
1292
1293 // Get identifier properties.
1294 vkGetPhysicalDeviceProperties(gpu, &gpu_props);
1295
1296 device_name = gpu_props.deviceName;
1297 device_type = gpu_props.deviceType;
1298 pipeline_cache_id = String::hex_encode_buffer(gpu_props.pipelineCacheUUID, VK_UUID_SIZE);
1299 pipeline_cache_id += "-driver-" + itos(gpu_props.driverVersion);
1300 {
1301 device_vendor = "Unknown";
1302 uint32_t vendor_idx = 0;
1303 while (vendor_names[vendor_idx].name != nullptr) {
1304 if (gpu_props.vendorID == vendor_names[vendor_idx].id) {
1305 device_vendor = vendor_names[vendor_idx].name;
1306 break;
1307 }
1308 vendor_idx++;
1309 }
1310 }
1311
1312 // Get device version
1313 device_api_version = gpu_props.apiVersion;
1314
1315 String rendering_method;
1316 if (OS::get_singleton()->get_current_rendering_method() == "mobile") {
1317 rendering_method = "Forward Mobile";
1318 } else {
1319 rendering_method = "Forward+";
1320 }
1321
1322 // Output our device version
1323 print_line(vformat("Vulkan API %s - %s - Using Vulkan Device #%d: %s - %s", get_device_api_version(), rendering_method, device_index, device_vendor, device_name));
1324
1325 {
1326 Error _err = _initialize_device_extensions();
1327 if (_err != OK) {
1328 return _err;
1329 }
1330 }
1331
1332 // Call with nullptr data to get count.
1333 vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr);
1334 ERR_FAIL_COND_V(queue_family_count == 0, ERR_CANT_CREATE);
1335
1336 queue_props = (VkQueueFamilyProperties *)malloc(queue_family_count * sizeof(VkQueueFamilyProperties));
1337 vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, queue_props);
1338 // Query fine-grained feature support for this device.
1339 // If app has specific feature requirements it should check supported
1340 // features based on this query
1341 vkGetPhysicalDeviceFeatures(gpu, &physical_device_features);
1342
1343 // Check required features and abort if any of them is missing.
1344 if (!physical_device_features.imageCubeArray || !physical_device_features.independentBlend) {
1345 String error_string = vformat("Your GPU (%s) does not support the following features which are required to use Vulkan-based renderers in Godot:\n\n", device_name);
1346 if (!physical_device_features.imageCubeArray) {
1347 error_string += "- No support for image cube arrays.\n";
1348 }
1349 if (!physical_device_features.independentBlend) {
1350 error_string += "- No support for independentBlend.\n";
1351 }
1352 error_string += "\nThis is usually a hardware limitation, so updating graphics drivers won't help in most cases.";
1353
1354#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
1355 // Android/iOS platform ports currently don't exit themselves when this method returns `ERR_CANT_CREATE`.
1356 OS::get_singleton()->alert(error_string + "\nClick OK to exit (black screen will be visible).");
1357#else
1358 OS::get_singleton()->alert(error_string + "\nClick OK to exit.");
1359#endif
1360
1361 return ERR_CANT_CREATE;
1362 }
1363
1364 physical_device_features.robustBufferAccess = false; // Turn off robust buffer access, which can hamper performance on some hardware.
1365
1366#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
1367 { \
1368 fp##entrypoint = (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \
1369 ERR_FAIL_COND_V_MSG(fp##entrypoint == nullptr, ERR_CANT_CREATE, \
1370 "vkGetInstanceProcAddr failed to find vk" #entrypoint); \
1371 }
1372
1373 GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfaceSupportKHR);
1374 GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfaceCapabilitiesKHR);
1375 GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfaceFormatsKHR);
1376 GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfacePresentModesKHR);
1377 GET_INSTANCE_PROC_ADDR(inst, GetSwapchainImagesKHR);
1378
1379 // Gets capability info for current Vulkan driver.
1380 {
1381 Error res = _check_capabilities();
1382 if (res != OK) {
1383 return res;
1384 }
1385 }
1386
1387 device_initialized = true;
1388 return OK;
1389}
1390
1391Error VulkanContext::_create_device() {
1392 VkResult err;
1393 float queue_priorities[1] = { 0.0 };
1394 VkDeviceQueueCreateInfo queues[2];
1395 queues[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1396 queues[0].pNext = nullptr;
1397 queues[0].queueFamilyIndex = graphics_queue_family_index;
1398 queues[0].queueCount = 1;
1399 queues[0].pQueuePriorities = queue_priorities;
1400 queues[0].flags = 0;
1401
1402 // Before we retrieved what is supported, here we tell Vulkan we want to enable these features using the same structs.
1403 void *nextptr = nullptr;
1404
1405 VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features = {
1406 /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR,
1407 /*pNext*/ nextptr,
1408 /*shaderFloat16*/ shader_capabilities.shader_float16_is_supported,
1409 /*shaderInt8*/ shader_capabilities.shader_int8_is_supported,
1410 };
1411 nextptr = &shader_features;
1412
1413 VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = {};
1414 if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) {
1415 // Insert into our chain to enable these features if they are available.
1416 vrs_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
1417 vrs_features.pNext = nextptr;
1418 vrs_features.pipelineFragmentShadingRate = vrs_capabilities.pipeline_vrs_supported;
1419 vrs_features.primitiveFragmentShadingRate = vrs_capabilities.primitive_vrs_supported;
1420 vrs_features.attachmentFragmentShadingRate = vrs_capabilities.attachment_vrs_supported;
1421
1422 nextptr = &vrs_features;
1423 }
1424
1425 VkPhysicalDeviceVulkan11Features vulkan11features = {};
1426 VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {};
1427 VkPhysicalDeviceMultiviewFeatures multiview_features = {};
1428 if (device_api_version >= VK_API_VERSION_1_2) {
1429 // In Vulkan 1.2 and newer we use a newer struct to enable various features.
1430
1431 vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
1432 vulkan11features.pNext = nextptr;
1433 vulkan11features.storageBuffer16BitAccess = storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported;
1434 vulkan11features.uniformAndStorageBuffer16BitAccess = storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported;
1435 vulkan11features.storagePushConstant16 = storage_buffer_capabilities.storage_push_constant_16_is_supported;
1436 vulkan11features.storageInputOutput16 = storage_buffer_capabilities.storage_input_output_16;
1437 vulkan11features.multiview = multiview_capabilities.is_supported;
1438 vulkan11features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
1439 vulkan11features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;
1440 vulkan11features.variablePointersStorageBuffer = 0;
1441 vulkan11features.variablePointers = 0;
1442 vulkan11features.protectedMemory = 0;
1443 vulkan11features.samplerYcbcrConversion = 0;
1444 vulkan11features.shaderDrawParameters = 0;
1445 nextptr = &vulkan11features;
1446 } else {
1447 // On Vulkan 1.0 and 1.1 we use our older structs to initialize these features.
1448 storage_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR;
1449 storage_feature.pNext = nextptr;
1450 storage_feature.storageBuffer16BitAccess = storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported;
1451 storage_feature.uniformAndStorageBuffer16BitAccess = storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported;
1452 storage_feature.storagePushConstant16 = storage_buffer_capabilities.storage_push_constant_16_is_supported;
1453 storage_feature.storageInputOutput16 = storage_buffer_capabilities.storage_input_output_16;
1454 nextptr = &storage_feature;
1455
1456 if (device_api_version >= VK_API_VERSION_1_1) { // any Vulkan 1.1.x version
1457 multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
1458 multiview_features.pNext = nextptr;
1459 multiview_features.multiview = multiview_capabilities.is_supported;
1460 multiview_features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
1461 multiview_features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;
1462 nextptr = &multiview_features;
1463 }
1464 }
1465
1466 uint32_t enabled_extension_count = 0;
1467 const char *enabled_extension_names[MAX_EXTENSIONS];
1468 ERR_FAIL_COND_V(enabled_device_extension_names.size() > MAX_EXTENSIONS, ERR_CANT_CREATE);
1469 for (const CharString &extension_name : enabled_device_extension_names) {
1470 enabled_extension_names[enabled_extension_count++] = extension_name.ptr();
1471 }
1472
1473 VkDeviceCreateInfo sdevice = {
1474 /*sType*/ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1475 /*pNext*/ nextptr,
1476 /*flags*/ 0,
1477 /*queueCreateInfoCount*/ 1,
1478 /*pQueueCreateInfos*/ queues,
1479 /*enabledLayerCount*/ 0,
1480 /*ppEnabledLayerNames*/ nullptr,
1481 /*enabledExtensionCount*/ enabled_extension_count,
1482 /*ppEnabledExtensionNames*/ (const char *const *)enabled_extension_names,
1483 /*pEnabledFeatures*/ &physical_device_features, // If specific features are required, pass them in here.
1484 };
1485 if (separate_present_queue) {
1486 queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1487 queues[1].pNext = nullptr;
1488 queues[1].queueFamilyIndex = present_queue_family_index;
1489 queues[1].queueCount = 1;
1490 queues[1].pQueuePriorities = queue_priorities;
1491 queues[1].flags = 0;
1492 sdevice.queueCreateInfoCount = 2;
1493 }
1494
1495 if (vulkan_hooks) {
1496 if (!vulkan_hooks->create_vulkan_device(&sdevice, &device)) {
1497 return ERR_CANT_CREATE;
1498 }
1499 } else {
1500 err = vkCreateDevice(gpu, &sdevice, nullptr, &device);
1501 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
1502 }
1503
1504 return OK;
1505}
1506
1507Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) {
1508 // Iterate over each queue to learn whether it supports presenting:
1509 VkBool32 *supportsPresent = (VkBool32 *)malloc(queue_family_count * sizeof(VkBool32));
1510 for (uint32_t i = 0; i < queue_family_count; i++) {
1511 fpGetPhysicalDeviceSurfaceSupportKHR(gpu, i, p_surface, &supportsPresent[i]);
1512 }
1513
1514 // Search for a graphics and a present queue in the array of queue
1515 // families, try to find one that supports both.
1516 uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
1517 uint32_t presentQueueFamilyIndex = UINT32_MAX;
1518 for (uint32_t i = 0; i < queue_family_count; i++) {
1519 if ((queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
1520 if (graphicsQueueFamilyIndex == UINT32_MAX) {
1521 graphicsQueueFamilyIndex = i;
1522 }
1523
1524 if (supportsPresent[i] == VK_TRUE) {
1525 graphicsQueueFamilyIndex = i;
1526 presentQueueFamilyIndex = i;
1527 break;
1528 }
1529 }
1530 }
1531
1532 if (presentQueueFamilyIndex == UINT32_MAX) {
1533 // If didn't find a queue that supports both graphics and present, then
1534 // find a separate present queue.
1535 for (uint32_t i = 0; i < queue_family_count; ++i) {
1536 if (supportsPresent[i] == VK_TRUE) {
1537 presentQueueFamilyIndex = i;
1538 break;
1539 }
1540 }
1541 }
1542
1543 free(supportsPresent);
1544
1545 // Generate error if could not find both a graphics and a present queue.
1546 ERR_FAIL_COND_V_MSG(graphicsQueueFamilyIndex == UINT32_MAX || presentQueueFamilyIndex == UINT32_MAX, ERR_CANT_CREATE,
1547 "Could not find both graphics and present queues\n");
1548
1549 graphics_queue_family_index = graphicsQueueFamilyIndex;
1550 present_queue_family_index = presentQueueFamilyIndex;
1551 separate_present_queue = (graphics_queue_family_index != present_queue_family_index);
1552
1553 _create_device();
1554
1555 static PFN_vkGetDeviceProcAddr g_gdpa = nullptr;
1556#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
1557 { \
1558 if (!g_gdpa) \
1559 g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(inst, "vkGetDeviceProcAddr"); \
1560 fp##entrypoint = (PFN_vk##entrypoint)g_gdpa(dev, "vk" #entrypoint); \
1561 ERR_FAIL_COND_V_MSG(fp##entrypoint == nullptr, ERR_CANT_CREATE, \
1562 "vkGetDeviceProcAddr failed to find vk" #entrypoint); \
1563 }
1564
1565 GET_DEVICE_PROC_ADDR(device, CreateSwapchainKHR);
1566 GET_DEVICE_PROC_ADDR(device, DestroySwapchainKHR);
1567 GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR);
1568 GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR);
1569 GET_DEVICE_PROC_ADDR(device, QueuePresentKHR);
1570 if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
1571 GET_DEVICE_PROC_ADDR(device, GetRefreshCycleDurationGOOGLE);
1572 GET_DEVICE_PROC_ADDR(device, GetPastPresentationTimingGOOGLE);
1573 }
1574
1575 vkGetDeviceQueue(device, graphics_queue_family_index, 0, &graphics_queue);
1576
1577 if (!separate_present_queue) {
1578 present_queue = graphics_queue;
1579 } else {
1580 vkGetDeviceQueue(device, present_queue_family_index, 0, &present_queue);
1581 }
1582
1583 // Get the list of VkFormat's that are supported:
1584 uint32_t formatCount;
1585 VkResult err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, p_surface, &formatCount, nullptr);
1586 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
1587 VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
1588 err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, p_surface, &formatCount, surfFormats);
1589 if (err) {
1590 free(surfFormats);
1591 ERR_FAIL_V(ERR_CANT_CREATE);
1592 }
1593 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
1594 // the surface has no preferred format. Otherwise, at least one
1595 // supported format will be returned.
1596 if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
1597 format = VK_FORMAT_B8G8R8A8_UNORM;
1598 color_space = surfFormats[0].colorSpace;
1599 } else {
1600 // These should be ordered with the ones we want to use on top and fallback modes further down
1601 // we want a 32bit RGBA unsigned normalized buffer or similar.
1602 const VkFormat allowed_formats[] = {
1603 VK_FORMAT_B8G8R8A8_UNORM,
1604 VK_FORMAT_R8G8B8A8_UNORM
1605 };
1606 uint32_t allowed_formats_count = sizeof(allowed_formats) / sizeof(VkFormat);
1607
1608 if (formatCount < 1) {
1609 free(surfFormats);
1610 ERR_FAIL_V_MSG(ERR_CANT_CREATE, "formatCount less than 1");
1611 }
1612
1613 // Find the first format that we support.
1614 format = VK_FORMAT_UNDEFINED;
1615 for (uint32_t af = 0; af < allowed_formats_count && format == VK_FORMAT_UNDEFINED; af++) {
1616 for (uint32_t sf = 0; sf < formatCount && format == VK_FORMAT_UNDEFINED; sf++) {
1617 if (surfFormats[sf].format == allowed_formats[af]) {
1618 format = surfFormats[sf].format;
1619 color_space = surfFormats[sf].colorSpace;
1620 }
1621 }
1622 }
1623
1624 if (format == VK_FORMAT_UNDEFINED) {
1625 free(surfFormats);
1626 ERR_FAIL_V_MSG(ERR_CANT_CREATE, "No usable surface format found.");
1627 }
1628 }
1629
1630 free(surfFormats);
1631
1632 Error serr = _create_semaphores();
1633 if (serr) {
1634 return serr;
1635 }
1636
1637 queues_initialized = true;
1638 return OK;
1639}
1640
1641Error VulkanContext::_create_semaphores() {
1642 VkResult err;
1643
1644 // Create semaphores to synchronize acquiring presentable buffers before
1645 // rendering and waiting for drawing to be complete before presenting.
1646 VkSemaphoreCreateInfo semaphoreCreateInfo = {
1647 /*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
1648 /*pNext*/ nullptr,
1649 /*flags*/ 0,
1650 };
1651
1652 // Create fences that we can use to throttle if we get too far
1653 // ahead of the image presents.
1654 VkFenceCreateInfo fence_ci = {
1655 /*sType*/ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1656 /*pNext*/ nullptr,
1657 /*flags*/ VK_FENCE_CREATE_SIGNALED_BIT
1658 };
1659 for (uint32_t i = 0; i < FRAME_LAG; i++) {
1660 err = vkCreateFence(device, &fence_ci, nullptr, &fences[i]);
1661 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
1662
1663 err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &draw_complete_semaphores[i]);
1664 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
1665
1666 if (separate_present_queue) {
1667 err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &image_ownership_semaphores[i]);
1668 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
1669 }
1670 }
1671 frame_index = 0;
1672
1673 // Get Memory information and properties.
1674 vkGetPhysicalDeviceMemoryProperties(gpu, &memory_properties);
1675
1676 return OK;
1677}
1678
1679bool VulkanContext::_use_validation_layers() {
1680 return Engine::get_singleton()->is_validation_layers_enabled();
1681}
1682
1683VkExtent2D VulkanContext::_compute_swapchain_extent(const VkSurfaceCapabilitiesKHR &p_surf_capabilities, int *p_window_width, int *p_window_height) const {
1684 // Width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
1685 if (p_surf_capabilities.currentExtent.width == 0xFFFFFFFF) {
1686 // If the surface size is undefined, the size is set to the size
1687 // of the images requested, which must fit within the minimum and
1688 // maximum values.
1689 VkExtent2D extent = {};
1690 extent.width = CLAMP((uint32_t)(*p_window_width), p_surf_capabilities.minImageExtent.width, p_surf_capabilities.maxImageExtent.width);
1691 extent.height = CLAMP((uint32_t)(*p_window_height), p_surf_capabilities.minImageExtent.height, p_surf_capabilities.maxImageExtent.height);
1692 return extent;
1693 } else {
1694 // If the surface size is defined, the swap chain size must match.
1695 *p_window_width = p_surf_capabilities.currentExtent.width;
1696 *p_window_height = p_surf_capabilities.currentExtent.height;
1697 return p_surf_capabilities.currentExtent;
1698 }
1699}
1700
1701Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height) {
1702 ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
1703
1704 if (!device_initialized) {
1705 Error err = _create_physical_device(p_surface);
1706 ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
1707 }
1708
1709 if (!queues_initialized) {
1710 // We use a single GPU, but we need a surface to initialize the
1711 // queues, so this process must be deferred until a surface
1712 // is created.
1713 Error err = _initialize_queues(p_surface);
1714 ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
1715 }
1716
1717 Window window;
1718 window.surface = p_surface;
1719 window.width = p_width;
1720 window.height = p_height;
1721 window.vsync_mode = p_vsync_mode;
1722 Error err = _update_swap_chain(&window);
1723 ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
1724
1725 windows[p_window_id] = window;
1726 return OK;
1727}
1728
1729void VulkanContext::window_resize(DisplayServer::WindowID p_window, int p_width, int p_height) {
1730 ERR_FAIL_COND(!windows.has(p_window));
1731 windows[p_window].width = p_width;
1732 windows[p_window].height = p_height;
1733 _update_swap_chain(&windows[p_window]);
1734}
1735
1736int VulkanContext::window_get_width(DisplayServer::WindowID p_window) {
1737 ERR_FAIL_COND_V(!windows.has(p_window), -1);
1738 return windows[p_window].width;
1739}
1740
1741int VulkanContext::window_get_height(DisplayServer::WindowID p_window) {
1742 ERR_FAIL_COND_V(!windows.has(p_window), -1);
1743 return windows[p_window].height;
1744}
1745
1746bool VulkanContext::window_is_valid_swapchain(DisplayServer::WindowID p_window) {
1747 ERR_FAIL_COND_V(!windows.has(p_window), false);
1748 Window *w = &windows[p_window];
1749 return w->swapchain_image_resources != VK_NULL_HANDLE;
1750}
1751
1752VkRenderPass VulkanContext::window_get_render_pass(DisplayServer::WindowID p_window) {
1753 ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE);
1754 Window *w = &windows[p_window];
1755 // Vulkan use of currentbuffer.
1756 return w->render_pass;
1757}
1758
1759VkFramebuffer VulkanContext::window_get_framebuffer(DisplayServer::WindowID p_window) {
1760 ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE);
1761 ERR_FAIL_COND_V(!buffers_prepared, VK_NULL_HANDLE);
1762 Window *w = &windows[p_window];
1763 // Vulkan use of currentbuffer.
1764 if (w->swapchain_image_resources != VK_NULL_HANDLE) {
1765 return w->swapchain_image_resources[w->current_buffer].framebuffer;
1766 } else {
1767 return VK_NULL_HANDLE;
1768 }
1769}
1770
1771void VulkanContext::window_destroy(DisplayServer::WindowID p_window_id) {
1772 ERR_FAIL_COND(!windows.has(p_window_id));
1773 _clean_up_swap_chain(&windows[p_window_id]);
1774
1775 vkDestroySurfaceKHR(inst, windows[p_window_id].surface, nullptr);
1776 windows.erase(p_window_id);
1777}
1778
1779Error VulkanContext::_clean_up_swap_chain(Window *window) {
1780 if (!window->swapchain) {
1781 return OK;
1782 }
1783 vkDeviceWaitIdle(device);
1784
1785 // This destroys images associated it seems.
1786 fpDestroySwapchainKHR(device, window->swapchain, nullptr);
1787 window->swapchain = VK_NULL_HANDLE;
1788 vkDestroyRenderPass(device, window->render_pass, nullptr);
1789 window->render_pass = VK_NULL_HANDLE;
1790 if (window->swapchain_image_resources) {
1791 for (uint32_t i = 0; i < swapchainImageCount; i++) {
1792 vkDestroyImageView(device, window->swapchain_image_resources[i].view, nullptr);
1793 vkDestroyFramebuffer(device, window->swapchain_image_resources[i].framebuffer, nullptr);
1794 }
1795
1796 free(window->swapchain_image_resources);
1797 window->swapchain_image_resources = nullptr;
1798 swapchainImageCount = 0;
1799 }
1800 if (separate_present_queue) {
1801 vkDestroyCommandPool(device, window->present_cmd_pool, nullptr);
1802 }
1803
1804 for (uint32_t i = 0; i < FRAME_LAG; i++) {
1805 // Destroy the semaphores now (we'll re-create it later if we have to).
1806 // We must do this because the semaphore cannot be reused if it's in a signaled state
1807 // (which happens if vkAcquireNextImageKHR returned VK_ERROR_OUT_OF_DATE_KHR or VK_SUBOPTIMAL_KHR)
1808 // The only way to reset it would be to present the swapchain... the one we just destroyed.
1809 // And the API has no way to "unsignal" the semaphore.
1810 vkDestroySemaphore(device, window->image_acquired_semaphores[i], nullptr);
1811 window->image_acquired_semaphores[i] = 0;
1812 }
1813
1814 return OK;
1815}
1816
1817Error VulkanContext::_update_swap_chain(Window *window) {
1818 VkResult err;
1819
1820 if (window->swapchain) {
1821 _clean_up_swap_chain(window);
1822 }
1823
1824 // Check the surface capabilities and formats.
1825 VkSurfaceCapabilitiesKHR surfCapabilities;
1826 err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, window->surface, &surfCapabilities);
1827 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
1828
1829 {
1830 VkBool32 supports = VK_FALSE;
1831 err = vkGetPhysicalDeviceSurfaceSupportKHR(
1832 gpu, present_queue_family_index, window->surface, &supports);
1833 ERR_FAIL_COND_V_MSG(err != VK_SUCCESS || supports == false, ERR_CANT_CREATE,
1834 "Window's surface is not supported by device. Did the GPU go offline? Was the window "
1835 "created on another monitor? Check previous errors & try launching with "
1836 "--gpu-validation.");
1837 }
1838
1839 uint32_t presentModeCount;
1840 err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, nullptr);
1841 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
1842 VkPresentModeKHR *presentModes = (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
1843 ERR_FAIL_COND_V(!presentModes, ERR_CANT_CREATE);
1844 err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, presentModes);
1845 if (err) {
1846 free(presentModes);
1847 ERR_FAIL_V(ERR_CANT_CREATE);
1848 }
1849
1850 VkExtent2D swapchainExtent = _compute_swapchain_extent(surfCapabilities, &window->width, &window->height);
1851
1852 if (window->width == 0 || window->height == 0) {
1853 free(presentModes);
1854 // Likely window minimized, no swapchain created.
1855 return ERR_SKIP;
1856 }
1857 // The FIFO present mode is guaranteed by the spec to be supported
1858 // and to have no tearing. It's a great default present mode to use.
1859
1860 // There are times when you may wish to use another present mode. The
1861 // following code shows how to select them, and the comments provide some
1862 // reasons you may wish to use them.
1863 //
1864 // It should be noted that Vulkan 1.0 doesn't provide a method for
1865 // synchronizing rendering with the presentation engine's display. There
1866 // is a method provided for throttling rendering with the display, but
1867 // there are some presentation engines for which this method will not work.
1868 // If an application doesn't throttle its rendering, and if it renders much
1869 // faster than the refresh rate of the display, this can waste power on
1870 // mobile devices. That is because power is being spent rendering images
1871 // that may never be seen.
1872
1873 // VK_PRESENT_MODE_IMMEDIATE_KHR is for applications that don't care about
1874 // tearing, or have some way of synchronizing their rendering with the
1875 // display.
1876 // VK_PRESENT_MODE_MAILBOX_KHR may be useful for applications that
1877 // generally render a new presentable image every refresh cycle, but are
1878 // occasionally early. In this case, the application wants the new image
1879 // to be displayed instead of the previously-queued-for-presentation image
1880 // that has not yet been displayed.
1881 // VK_PRESENT_MODE_FIFO_RELAXED_KHR is for applications that generally
1882 // render a new presentable image every refresh cycle, but are occasionally
1883 // late. In this case (perhaps because of stuttering/latency concerns),
1884 // the application wants the late image to be immediately displayed, even
1885 // though that may mean some tearing.
1886
1887 VkPresentModeKHR requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR;
1888 switch (window->vsync_mode) {
1889 case DisplayServer::VSYNC_MAILBOX:
1890 requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_MAILBOX_KHR;
1891 break;
1892 case DisplayServer::VSYNC_ADAPTIVE:
1893 requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_RELAXED_KHR;
1894 break;
1895 case DisplayServer::VSYNC_ENABLED:
1896 requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR;
1897 break;
1898 case DisplayServer::VSYNC_DISABLED:
1899 requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_IMMEDIATE_KHR;
1900 break;
1901 }
1902
1903 // Check if the requested mode is available.
1904 bool present_mode_available = false;
1905 for (uint32_t i = 0; i < presentModeCount; i++) {
1906 if (presentModes[i] == requested_present_mode) {
1907 present_mode_available = true;
1908 }
1909 }
1910
1911 // Set the windows present mode if it is available, otherwise FIFO is used (guaranteed supported).
1912 if (present_mode_available) {
1913 if (window->presentMode != requested_present_mode) {
1914 window->presentMode = requested_present_mode;
1915 print_verbose("Using present mode: " + String(string_VkPresentModeKHR(window->presentMode)));
1916 }
1917 } else {
1918 String present_mode_string;
1919 switch (window->vsync_mode) {
1920 case DisplayServer::VSYNC_MAILBOX:
1921 present_mode_string = "Mailbox";
1922 break;
1923 case DisplayServer::VSYNC_ADAPTIVE:
1924 present_mode_string = "Adaptive";
1925 break;
1926 case DisplayServer::VSYNC_ENABLED:
1927 present_mode_string = "Enabled";
1928 break;
1929 case DisplayServer::VSYNC_DISABLED:
1930 present_mode_string = "Disabled";
1931 break;
1932 }
1933 WARN_PRINT(vformat("The requested V-Sync mode %s is not available. Falling back to V-Sync mode Enabled.", present_mode_string));
1934 window->vsync_mode = DisplayServer::VSYNC_ENABLED; // Set to default.
1935 }
1936
1937 free(presentModes);
1938
1939 // Determine the number of VkImages to use in the swap chain.
1940 // Application desires to acquire 3 images at a time for triple
1941 // buffering.
1942 uint32_t desiredNumOfSwapchainImages = 3;
1943 if (desiredNumOfSwapchainImages < surfCapabilities.minImageCount) {
1944 desiredNumOfSwapchainImages = surfCapabilities.minImageCount;
1945 }
1946 // If maxImageCount is 0, we can ask for as many images as we want;
1947 // otherwise we're limited to maxImageCount.
1948 if ((surfCapabilities.maxImageCount > 0) && (desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) {
1949 // Application must settle for fewer images than desired.
1950 desiredNumOfSwapchainImages = surfCapabilities.maxImageCount;
1951 }
1952
1953 VkSurfaceTransformFlagsKHR preTransform;
1954 if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
1955 preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
1956 } else {
1957 preTransform = surfCapabilities.currentTransform;
1958 }
1959
1960 VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1961
1962 if (OS::get_singleton()->is_layered_allowed() || !(surfCapabilities.supportedCompositeAlpha & compositeAlpha)) {
1963 // Find a supported composite alpha mode - one of these is guaranteed to be set.
1964 VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = {
1965 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
1966 VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
1967 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
1968 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1969 };
1970
1971 for (uint32_t i = 0; i < ARRAY_SIZE(compositeAlphaFlags); i++) {
1972 if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
1973 compositeAlpha = compositeAlphaFlags[i];
1974 break;
1975 }
1976 }
1977 }
1978
1979 VkSwapchainCreateInfoKHR swapchain_ci = {
1980 /*sType*/ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
1981 /*pNext*/ nullptr,
1982 /*flags*/ 0,
1983 /*surface*/ window->surface,
1984 /*minImageCount*/ desiredNumOfSwapchainImages,
1985 /*imageFormat*/ format,
1986 /*imageColorSpace*/ color_space,
1987 /*imageExtent*/ {
1988 /*width*/ swapchainExtent.width,
1989 /*height*/ swapchainExtent.height,
1990 },
1991 /*imageArrayLayers*/ 1,
1992 /*imageUsage*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1993 /*imageSharingMode*/ VK_SHARING_MODE_EXCLUSIVE,
1994 /*queueFamilyIndexCount*/ 0,
1995 /*pQueueFamilyIndices*/ nullptr,
1996 /*preTransform*/ (VkSurfaceTransformFlagBitsKHR)preTransform,
1997 /*compositeAlpha*/ compositeAlpha,
1998 /*presentMode*/ window->presentMode,
1999 /*clipped*/ true,
2000 /*oldSwapchain*/ VK_NULL_HANDLE,
2001 };
2002
2003 err = fpCreateSwapchainKHR(device, &swapchain_ci, nullptr, &window->swapchain);
2004 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
2005
2006 uint32_t sp_image_count;
2007 err = fpGetSwapchainImagesKHR(device, window->swapchain, &sp_image_count, nullptr);
2008 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
2009
2010 if (swapchainImageCount == 0) {
2011 // Assign here for the first time.
2012 swapchainImageCount = sp_image_count;
2013 } else {
2014 ERR_FAIL_COND_V(swapchainImageCount != sp_image_count, ERR_BUG);
2015 }
2016
2017 VkImage *swapchainImages = (VkImage *)malloc(swapchainImageCount * sizeof(VkImage));
2018 ERR_FAIL_COND_V(!swapchainImages, ERR_CANT_CREATE);
2019 err = fpGetSwapchainImagesKHR(device, window->swapchain, &swapchainImageCount, swapchainImages);
2020 if (err) {
2021 free(swapchainImages);
2022 ERR_FAIL_V(ERR_CANT_CREATE);
2023 }
2024
2025 window->swapchain_image_resources =
2026 (SwapchainImageResources *)malloc(sizeof(SwapchainImageResources) * swapchainImageCount);
2027 if (!window->swapchain_image_resources) {
2028 free(swapchainImages);
2029 ERR_FAIL_V(ERR_CANT_CREATE);
2030 }
2031
2032 for (uint32_t i = 0; i < swapchainImageCount; i++) {
2033 VkImageViewCreateInfo color_image_view = {
2034 /*sType*/ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
2035 /*pNext*/ nullptr,
2036 /*flags*/ 0,
2037 /*image*/ swapchainImages[i],
2038 /*viewType*/ VK_IMAGE_VIEW_TYPE_2D,
2039 /*format*/ format,
2040 /*components*/ {
2041 /*r*/ VK_COMPONENT_SWIZZLE_R,
2042 /*g*/ VK_COMPONENT_SWIZZLE_G,
2043 /*b*/ VK_COMPONENT_SWIZZLE_B,
2044 /*a*/ VK_COMPONENT_SWIZZLE_A,
2045 },
2046 /*subresourceRange*/ { /*aspectMask*/ VK_IMAGE_ASPECT_COLOR_BIT,
2047 /*baseMipLevel*/ 0,
2048 /*levelCount*/ 1,
2049 /*baseArrayLayer*/ 0,
2050 /*layerCount*/ 1 },
2051 };
2052
2053 window->swapchain_image_resources[i].image = swapchainImages[i];
2054
2055 color_image_view.image = window->swapchain_image_resources[i].image;
2056
2057 err = vkCreateImageView(device, &color_image_view, nullptr, &window->swapchain_image_resources[i].view);
2058 if (err) {
2059 free(swapchainImages);
2060 ERR_FAIL_V(ERR_CANT_CREATE);
2061 }
2062 }
2063
2064 free(swapchainImages);
2065
2066 /******** FRAMEBUFFER ************/
2067
2068 {
2069 const VkAttachmentDescription2KHR attachment = {
2070 /*sType*/ VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR,
2071 /*pNext*/ nullptr,
2072 /*flags*/ 0,
2073 /*format*/ format,
2074 /*samples*/ VK_SAMPLE_COUNT_1_BIT,
2075 /*loadOp*/ VK_ATTACHMENT_LOAD_OP_CLEAR,
2076 /*storeOp*/ VK_ATTACHMENT_STORE_OP_STORE,
2077 /*stencilLoadOp*/ VK_ATTACHMENT_LOAD_OP_DONT_CARE,
2078 /*stencilStoreOp*/ VK_ATTACHMENT_STORE_OP_DONT_CARE,
2079 /*initialLayout*/ VK_IMAGE_LAYOUT_UNDEFINED,
2080 /*finalLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
2081
2082 };
2083 const VkAttachmentReference2KHR color_reference = {
2084 /*sType*/ VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR,
2085 /*pNext*/ nullptr,
2086 /*attachment*/ 0,
2087 /*layout*/ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
2088 /*aspectMask*/ 0,
2089 };
2090
2091 const VkSubpassDescription2KHR subpass = {
2092 /*sType*/ VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR,
2093 /*pNext*/ nullptr,
2094 /*flags*/ 0,
2095 /*pipelineBindPoint*/ VK_PIPELINE_BIND_POINT_GRAPHICS,
2096 /*viewMask*/ 0,
2097 /*inputAttachmentCount*/ 0,
2098 /*pInputAttachments*/ nullptr,
2099 /*colorAttachmentCount*/ 1,
2100 /*pColorAttachments*/ &color_reference,
2101 /*pResolveAttachments*/ nullptr,
2102 /*pDepthStencilAttachment*/ nullptr,
2103 /*preserveAttachmentCount*/ 0,
2104 /*pPreserveAttachments*/ nullptr,
2105 };
2106
2107 const VkRenderPassCreateInfo2KHR rp_info = {
2108 /*sType*/ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR,
2109 /*pNext*/ nullptr,
2110 /*flags*/ 0,
2111 /*attachmentCount*/ 1,
2112 /*pAttachments*/ &attachment,
2113 /*subpassCount*/ 1,
2114 /*pSubpasses*/ &subpass,
2115 /*dependencyCount*/ 0,
2116 /*pDependencies*/ nullptr,
2117 /*correlatedViewMaskCount*/ 0,
2118 /*pCorrelatedViewMasks*/ nullptr,
2119 };
2120
2121 err = vkCreateRenderPass2KHR(device, &rp_info, nullptr, &window->render_pass);
2122 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
2123
2124 for (uint32_t i = 0; i < swapchainImageCount; i++) {
2125 const VkFramebufferCreateInfo fb_info = {
2126 /*sType*/ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
2127 /*pNext*/ nullptr,
2128 /*flags*/ 0,
2129 /*renderPass*/ window->render_pass,
2130 /*attachmentCount*/ 1,
2131 /*pAttachments*/ &window->swapchain_image_resources[i].view,
2132 /*width*/ (uint32_t)window->width,
2133 /*height*/ (uint32_t)window->height,
2134 /*layers*/ 1,
2135 };
2136
2137 err = vkCreateFramebuffer(device, &fb_info, nullptr, &window->swapchain_image_resources[i].framebuffer);
2138 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
2139 }
2140 }
2141
2142 /******** SEPARATE PRESENT QUEUE ************/
2143
2144 if (separate_present_queue) {
2145 const VkCommandPoolCreateInfo present_cmd_pool_info = {
2146 /*sType*/ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
2147 /*pNext*/ nullptr,
2148 /*flags*/ 0,
2149 /*queueFamilyIndex*/ present_queue_family_index,
2150 };
2151 err = vkCreateCommandPool(device, &present_cmd_pool_info, nullptr, &window->present_cmd_pool);
2152 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
2153 const VkCommandBufferAllocateInfo present_cmd_info = {
2154 /*sType*/ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
2155 /*pNext*/ nullptr,
2156 /*commandPool*/ window->present_cmd_pool,
2157 /*level*/ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
2158 /*commandBufferCount*/ 1,
2159 };
2160 for (uint32_t i = 0; i < swapchainImageCount; i++) {
2161 err = vkAllocateCommandBuffers(device, &present_cmd_info,
2162 &window->swapchain_image_resources[i].graphics_to_present_cmd);
2163 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
2164
2165 const VkCommandBufferBeginInfo cmd_buf_info = {
2166 /*sType*/ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
2167 /*pNext*/ nullptr,
2168 /*flags*/ VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
2169 /*pInheritanceInfo*/ nullptr,
2170 };
2171 err = vkBeginCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd, &cmd_buf_info);
2172 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
2173
2174 VkImageMemoryBarrier image_ownership_barrier = {
2175 /*sType*/ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
2176 /*pNext*/ nullptr,
2177 /*srcAccessMask*/ 0,
2178 /*dstAccessMask*/ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
2179 /*oldLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
2180 /*newLayout*/ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
2181 /*srcQueueFamilyIndex*/ graphics_queue_family_index,
2182 /*dstQueueFamilyIndex*/ present_queue_family_index,
2183 /*image*/ window->swapchain_image_resources[i].image,
2184 /*subresourceRange*/ { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
2185 };
2186
2187 vkCmdPipelineBarrier(window->swapchain_image_resources[i].graphics_to_present_cmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2188 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_ownership_barrier);
2189 err = vkEndCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd);
2190 ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
2191 }
2192 }
2193
2194 // Reset current buffer.
2195 window->current_buffer = 0;
2196
2197 VkSemaphoreCreateInfo semaphoreCreateInfo = {
2198 /*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
2199 /*pNext*/ nullptr,
2200 /*flags*/ 0,
2201 };
2202
2203 for (uint32_t i = 0; i < FRAME_LAG; i++) {
2204 VkResult vkerr = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &window->image_acquired_semaphores[i]);
2205 ERR_FAIL_COND_V(vkerr, ERR_CANT_CREATE);
2206 }
2207
2208 return OK;
2209}
2210
2211Error VulkanContext::initialize() {
2212#ifdef USE_VOLK
2213 if (volkInitialize() != VK_SUCCESS) {
2214 return FAILED;
2215 }
2216#endif
2217
2218 Error err = _create_instance();
2219 if (err != OK) {
2220 return err;
2221 }
2222
2223 return OK;
2224}
2225
2226void VulkanContext::set_setup_buffer(VkCommandBuffer p_command_buffer) {
2227 command_buffer_queue.write[0] = p_command_buffer;
2228}
2229
2230void VulkanContext::append_command_buffer(VkCommandBuffer p_command_buffer) {
2231 if (command_buffer_queue.size() <= command_buffer_count) {
2232 command_buffer_queue.resize(command_buffer_count + 1);
2233 }
2234
2235 command_buffer_queue.write[command_buffer_count] = p_command_buffer;
2236 command_buffer_count++;
2237}
2238
2239void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
2240 // Ensure everything else pending is executed.
2241 vkDeviceWaitIdle(device);
2242
2243 // Flush the pending setup buffer.
2244
2245 bool setup_flushable = p_flush_setup && command_buffer_queue[0];
2246 bool pending_flushable = p_flush_pending && command_buffer_count > 1;
2247
2248 if (setup_flushable) {
2249 // Use a fence to wait for everything done.
2250 VkSubmitInfo submit_info;
2251 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2252 submit_info.pNext = nullptr;
2253 submit_info.pWaitDstStageMask = nullptr;
2254 submit_info.waitSemaphoreCount = 0;
2255 submit_info.pWaitSemaphores = nullptr;
2256 submit_info.commandBufferCount = 1;
2257 submit_info.pCommandBuffers = command_buffer_queue.ptr();
2258 submit_info.signalSemaphoreCount = pending_flushable ? 1 : 0;
2259 submit_info.pSignalSemaphores = pending_flushable ? &draw_complete_semaphores[frame_index] : nullptr;
2260 VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
2261 command_buffer_queue.write[0] = nullptr;
2262 ERR_FAIL_COND(err);
2263 }
2264
2265 if (pending_flushable) {
2266 // Use a fence to wait for everything to finish.
2267
2268 VkSubmitInfo submit_info;
2269 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2270 submit_info.pNext = nullptr;
2271 VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
2272 submit_info.pWaitDstStageMask = setup_flushable ? &wait_stage_mask : nullptr;
2273 submit_info.waitSemaphoreCount = setup_flushable ? 1 : 0;
2274 submit_info.pWaitSemaphores = setup_flushable ? &draw_complete_semaphores[frame_index] : nullptr;
2275 submit_info.commandBufferCount = command_buffer_count - 1;
2276 submit_info.pCommandBuffers = command_buffer_queue.ptr() + 1;
2277 submit_info.signalSemaphoreCount = 0;
2278 submit_info.pSignalSemaphores = nullptr;
2279 VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
2280 command_buffer_count = 1;
2281 ERR_FAIL_COND(err);
2282 }
2283
2284 vkDeviceWaitIdle(device);
2285}
2286
2287Error VulkanContext::prepare_buffers() {
2288 if (!queues_initialized) {
2289 return OK;
2290 }
2291
2292 VkResult err;
2293
2294 // Ensure no more than FRAME_LAG renderings are outstanding.
2295 vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX);
2296 vkResetFences(device, 1, &fences[frame_index]);
2297
2298 for (KeyValue<int, Window> &E : windows) {
2299 Window *w = &E.value;
2300
2301 w->semaphore_acquired = false;
2302
2303 if (w->swapchain == VK_NULL_HANDLE) {
2304 continue;
2305 }
2306
2307 do {
2308 // Get the index of the next available swapchain image.
2309 err =
2310 fpAcquireNextImageKHR(device, w->swapchain, UINT64_MAX,
2311 w->image_acquired_semaphores[frame_index], VK_NULL_HANDLE, &w->current_buffer);
2312
2313 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2314 // Swapchain is out of date (e.g. the window was resized) and
2315 // must be recreated.
2316 print_verbose("Vulkan: Early out of date swapchain, recreating.");
2317 // resize_notify();
2318 _update_swap_chain(w);
2319 } else if (err == VK_SUBOPTIMAL_KHR) {
2320 // Swapchain is not as optimal as it could be, but the platform's
2321 // presentation engine will still present the image correctly.
2322 print_verbose("Vulkan: Early suboptimal swapchain, recreating.");
2323 Error swap_chain_err = _update_swap_chain(w);
2324 if (swap_chain_err == ERR_SKIP) {
2325 break;
2326 }
2327 } else if (err != VK_SUCCESS) {
2328 ERR_BREAK_MSG(err != VK_SUCCESS, "Vulkan: Did not create swapchain successfully. Error code: " + String(string_VkResult(err)));
2329 } else {
2330 w->semaphore_acquired = true;
2331 }
2332 } while (err != VK_SUCCESS);
2333 }
2334
2335 buffers_prepared = true;
2336
2337 return OK;
2338}
2339
2340Error VulkanContext::swap_buffers() {
2341 if (!queues_initialized) {
2342 return OK;
2343 }
2344
2345 // print_line("swapbuffers?");
2346 VkResult err;
2347
2348#if 0
2349 if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
2350 // Look at what happened to previous presents, and make appropriate
2351 // adjustments in timing.
2352 DemoUpdateTargetIPD(demo);
2353
2354 // Note: a real application would position its geometry to that it's in
2355 // the correct location for when the next image is presented. It might
2356 // also wait, so that there's less latency between any input and when
2357 // the next image is rendered/presented. This demo program is so
2358 // simple that it doesn't do either of those.
2359 }
2360#endif
2361 // Wait for the image acquired semaphore to be signaled to ensure
2362 // that the image won't be rendered to until the presentation
2363 // engine has fully released ownership to the application, and it is
2364 // okay to render to the image.
2365
2366 const VkCommandBuffer *commands_ptr = nullptr;
2367 uint32_t commands_to_submit = 0;
2368
2369 if (command_buffer_queue[0] == nullptr) {
2370 // No setup command, but commands to submit, submit from the first and skip command.
2371 if (command_buffer_count > 1) {
2372 commands_ptr = command_buffer_queue.ptr() + 1;
2373 commands_to_submit = command_buffer_count - 1;
2374 }
2375 } else {
2376 commands_ptr = command_buffer_queue.ptr();
2377 commands_to_submit = command_buffer_count;
2378 }
2379
2380 VkSemaphore *semaphores_to_acquire = (VkSemaphore *)alloca(windows.size() * sizeof(VkSemaphore));
2381 VkPipelineStageFlags *pipe_stage_flags = (VkPipelineStageFlags *)alloca(windows.size() * sizeof(VkPipelineStageFlags));
2382 uint32_t semaphores_to_acquire_count = 0;
2383
2384 for (KeyValue<int, Window> &E : windows) {
2385 Window *w = &E.value;
2386
2387 if (w->semaphore_acquired) {
2388 semaphores_to_acquire[semaphores_to_acquire_count] = w->image_acquired_semaphores[frame_index];
2389 pipe_stage_flags[semaphores_to_acquire_count] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2390 semaphores_to_acquire_count++;
2391 }
2392 }
2393
2394 VkSubmitInfo submit_info;
2395 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2396 submit_info.pNext = nullptr;
2397 submit_info.waitSemaphoreCount = semaphores_to_acquire_count;
2398 submit_info.pWaitSemaphores = semaphores_to_acquire;
2399 submit_info.pWaitDstStageMask = pipe_stage_flags;
2400 submit_info.commandBufferCount = commands_to_submit;
2401 submit_info.pCommandBuffers = commands_ptr;
2402 submit_info.signalSemaphoreCount = 1;
2403 submit_info.pSignalSemaphores = &draw_complete_semaphores[frame_index];
2404 err = vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]);
2405 ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Vulkan: Cannot submit graphics queue. Error code: " + String(string_VkResult(err)));
2406
2407 command_buffer_queue.write[0] = nullptr;
2408 command_buffer_count = 1;
2409
2410 if (separate_present_queue) {
2411 // If we are using separate queues, change image ownership to the
2412 // present queue before presenting, waiting for the draw complete
2413 // semaphore and signaling the ownership released semaphore when finished.
2414 VkFence nullFence = VK_NULL_HANDLE;
2415 pipe_stage_flags[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2416 submit_info.waitSemaphoreCount = 1;
2417 submit_info.pWaitSemaphores = &draw_complete_semaphores[frame_index];
2418 submit_info.commandBufferCount = 0;
2419
2420 VkCommandBuffer *cmdbufptr = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer *) * windows.size());
2421 submit_info.pCommandBuffers = cmdbufptr;
2422
2423 for (KeyValue<int, Window> &E : windows) {
2424 Window *w = &E.value;
2425
2426 if (w->swapchain == VK_NULL_HANDLE) {
2427 continue;
2428 }
2429 cmdbufptr[submit_info.commandBufferCount] = w->swapchain_image_resources[w->current_buffer].graphics_to_present_cmd;
2430 submit_info.commandBufferCount++;
2431 }
2432
2433 submit_info.signalSemaphoreCount = 1;
2434 submit_info.pSignalSemaphores = &image_ownership_semaphores[frame_index];
2435 err = vkQueueSubmit(present_queue, 1, &submit_info, nullFence);
2436 ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Vulkan: Cannot submit present queue. Error code: " + String(string_VkResult(err)));
2437 }
2438
2439 // If we are using separate queues, we have to wait for image ownership,
2440 // otherwise wait for draw complete.
2441 VkPresentInfoKHR present = {
2442 /*sType*/ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2443 /*pNext*/ nullptr,
2444 /*waitSemaphoreCount*/ 1,
2445 /*pWaitSemaphores*/ (separate_present_queue) ? &image_ownership_semaphores[frame_index] : &draw_complete_semaphores[frame_index],
2446 /*swapchainCount*/ 0,
2447 /*pSwapchain*/ nullptr,
2448 /*pImageIndices*/ nullptr,
2449 /*pResults*/ nullptr,
2450 };
2451
2452 VkSwapchainKHR *pSwapchains = (VkSwapchainKHR *)alloca(sizeof(VkSwapchainKHR *) * windows.size());
2453 uint32_t *pImageIndices = (uint32_t *)alloca(sizeof(uint32_t *) * windows.size());
2454
2455 present.pSwapchains = pSwapchains;
2456 present.pImageIndices = pImageIndices;
2457
2458 for (KeyValue<int, Window> &E : windows) {
2459 Window *w = &E.value;
2460
2461 if (w->swapchain == VK_NULL_HANDLE) {
2462 continue;
2463 }
2464 pSwapchains[present.swapchainCount] = w->swapchain;
2465 pImageIndices[present.swapchainCount] = w->current_buffer;
2466 present.swapchainCount++;
2467 }
2468
2469#if 0
2470 if (is_device_extension_enabled(VK_KHR_incremental_present_enabled)) {
2471 // If using VK_KHR_incremental_present, we provide a hint of the region
2472 // that contains changed content relative to the previously-presented
2473 // image. The implementation can use this hint in order to save
2474 // work/power (by only copying the region in the hint). The
2475 // implementation is free to ignore the hint though, and so we must
2476 // ensure that the entire image has the correctly-drawn content.
2477 uint32_t eighthOfWidth = width / 8;
2478 uint32_t eighthOfHeight = height / 8;
2479 VkRectLayerKHR rect = {
2480 /*offset.x*/ eighthOfWidth,
2481 /*offset.y*/ eighthOfHeight,
2482 /*extent.width*/ eighthOfWidth * 6,
2483 /*extent.height*/ eighthOfHeight * 6,
2484 /*layer*/ 0,
2485 };
2486 VkPresentRegionKHR region = {
2487 /*rectangleCount*/ 1,
2488 /*pRectangles*/ &rect,
2489 };
2490 VkPresentRegionsKHR regions = {
2491 /*sType*/ VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR,
2492 /*pNext*/ present.pNext,
2493 /*swapchainCount*/ present.swapchainCount,
2494 /*pRegions*/ &region,
2495 };
2496 present.pNext = &regions;
2497 }
2498#endif
2499
2500#if 0
2501 if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
2502 VkPresentTimeGOOGLE ptime;
2503 if (prev_desired_present_time == 0) {
2504 // This must be the first present for this swapchain.
2505 //
2506 // We don't know where we are relative to the presentation engine's
2507 // display's refresh cycle. We also don't know how long rendering
2508 // takes. Let's make a grossly-simplified assumption that the
2509 // desiredPresentTime should be half way between now and
2510 // now+target_IPD. We will adjust over time.
2511 uint64_t curtime = getTimeInNanoseconds();
2512 if (curtime == 0) {
2513 // Since we didn't find out the current time, don't give a
2514 // desiredPresentTime.
2515 ptime.desiredPresentTime = 0;
2516 } else {
2517 ptime.desiredPresentTime = curtime + (target_IPD >> 1);
2518 }
2519 } else {
2520 ptime.desiredPresentTime = (prev_desired_present_time + target_IPD);
2521 }
2522 ptime.presentID = next_present_id++;
2523 prev_desired_present_time = ptime.desiredPresentTime;
2524
2525 VkPresentTimesInfoGOOGLE present_time = {
2526 /*sType*/ VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE,
2527 /*pNext*/ present.pNext,
2528 /*swapchainCount*/ present.swapchainCount,
2529 /*pTimes*/ &ptime,
2530 };
2531 if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
2532 present.pNext = &present_time;
2533 }
2534 }
2535#endif
2536 // print_line("current buffer: " + itos(current_buffer));
2537 err = fpQueuePresentKHR(present_queue, &present);
2538
2539 frame_index += 1;
2540 frame_index %= FRAME_LAG;
2541
2542 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2543 // Swapchain is out of date (e.g. the window was resized) and
2544 // must be recreated.
2545 print_verbose("Vulkan queue submit: Swapchain is out of date, recreating.");
2546 resize_notify();
2547 } else if (err == VK_SUBOPTIMAL_KHR) {
2548 // Swapchain is not as optimal as it could be, but the platform's
2549 // presentation engine will still present the image correctly.
2550 print_verbose("Vulkan queue submit: Swapchain is suboptimal.");
2551 } else {
2552 ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Error code: " + String(string_VkResult(err)));
2553 }
2554
2555 buffers_prepared = false;
2556 return OK;
2557}
2558
2559void VulkanContext::resize_notify() {
2560}
2561
2562VkDevice VulkanContext::get_device() {
2563 return device;
2564}
2565
2566VkPhysicalDevice VulkanContext::get_physical_device() {
2567 return gpu;
2568}
2569
2570int VulkanContext::get_swapchain_image_count() const {
2571 return swapchainImageCount;
2572}
2573
2574VkQueue VulkanContext::get_graphics_queue() const {
2575 return graphics_queue;
2576}
2577
2578uint32_t VulkanContext::get_graphics_queue_family_index() const {
2579 return graphics_queue_family_index;
2580}
2581
2582VkFormat VulkanContext::get_screen_format() const {
2583 return format;
2584}
2585
2586VkPhysicalDeviceLimits VulkanContext::get_device_limits() const {
2587 return gpu_props.limits;
2588}
2589
2590RID VulkanContext::local_device_create() {
2591 LocalDevice ld;
2592
2593 { // Create device.
2594 VkResult err;
2595 float queue_priorities[1] = { 0.0 };
2596 VkDeviceQueueCreateInfo queues[2];
2597 queues[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
2598 queues[0].pNext = nullptr;
2599 queues[0].queueFamilyIndex = graphics_queue_family_index;
2600 queues[0].queueCount = 1;
2601 queues[0].pQueuePriorities = queue_priorities;
2602 queues[0].flags = 0;
2603
2604 uint32_t enabled_extension_count = 0;
2605 const char *enabled_extension_names[MAX_EXTENSIONS];
2606 ERR_FAIL_COND_V(enabled_device_extension_names.size() > MAX_EXTENSIONS, RID());
2607 for (const CharString &extension_name : enabled_device_extension_names) {
2608 enabled_extension_names[enabled_extension_count++] = extension_name.ptr();
2609 }
2610
2611 VkDeviceCreateInfo sdevice = {
2612 /*sType =*/VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
2613 /*pNext */ nullptr,
2614 /*flags */ 0,
2615 /*queueCreateInfoCount */ 1,
2616 /*pQueueCreateInfos */ queues,
2617 /*enabledLayerCount */ 0,
2618 /*ppEnabledLayerNames */ nullptr,
2619 /*enabledExtensionCount */ enabled_extension_count,
2620 /*ppEnabledExtensionNames */ (const char *const *)enabled_extension_names,
2621 /*pEnabledFeatures */ &physical_device_features, // If specific features are required, pass them in here.
2622 };
2623 err = vkCreateDevice(gpu, &sdevice, nullptr, &ld.device);
2624 ERR_FAIL_COND_V(err, RID());
2625 }
2626
2627 { // Create graphics queue.
2628
2629 vkGetDeviceQueue(ld.device, graphics_queue_family_index, 0, &ld.queue);
2630 }
2631
2632 return local_device_owner.make_rid(ld);
2633}
2634
2635VkDevice VulkanContext::local_device_get_vk_device(RID p_local_device) {
2636 LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
2637 return ld->device;
2638}
2639
2640void VulkanContext::local_device_push_command_buffers(RID p_local_device, const VkCommandBuffer *p_buffers, int p_count) {
2641 LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
2642 ERR_FAIL_COND(ld->waiting);
2643
2644 VkSubmitInfo submit_info;
2645 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2646 submit_info.pNext = nullptr;
2647 submit_info.pWaitDstStageMask = nullptr;
2648 submit_info.waitSemaphoreCount = 0;
2649 submit_info.pWaitSemaphores = nullptr;
2650 submit_info.commandBufferCount = p_count;
2651 submit_info.pCommandBuffers = p_buffers;
2652 submit_info.signalSemaphoreCount = 0;
2653 submit_info.pSignalSemaphores = nullptr;
2654
2655 VkResult err = vkQueueSubmit(ld->queue, 1, &submit_info, VK_NULL_HANDLE);
2656 if (err == VK_ERROR_OUT_OF_HOST_MEMORY) {
2657 print_line("Vulkan: Out of host memory!");
2658 }
2659 if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
2660 print_line("Vulkan: Out of device memory!");
2661 }
2662 if (err == VK_ERROR_DEVICE_LOST) {
2663 print_line("Vulkan: Device lost!");
2664 }
2665 ERR_FAIL_COND(err);
2666
2667 ld->waiting = true;
2668}
2669
2670void VulkanContext::local_device_sync(RID p_local_device) {
2671 LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
2672 ERR_FAIL_COND(!ld->waiting);
2673
2674 vkDeviceWaitIdle(ld->device);
2675 ld->waiting = false;
2676}
2677
2678void VulkanContext::local_device_free(RID p_local_device) {
2679 LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
2680 vkDestroyDevice(ld->device, nullptr);
2681 local_device_owner.free(p_local_device);
2682}
2683
2684void VulkanContext::command_begin_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color) {
2685 if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
2686 return;
2687 }
2688
2689 CharString cs = p_label_name.utf8();
2690 VkDebugUtilsLabelEXT label;
2691 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
2692 label.pNext = nullptr;
2693 label.pLabelName = cs.get_data();
2694 label.color[0] = p_color[0];
2695 label.color[1] = p_color[1];
2696 label.color[2] = p_color[2];
2697 label.color[3] = p_color[3];
2698 CmdBeginDebugUtilsLabelEXT(p_command_buffer, &label);
2699}
2700
2701void VulkanContext::command_insert_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color) {
2702 if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
2703 return;
2704 }
2705 CharString cs = p_label_name.utf8();
2706 VkDebugUtilsLabelEXT label;
2707 label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
2708 label.pNext = nullptr;
2709 label.pLabelName = cs.get_data();
2710 label.color[0] = p_color[0];
2711 label.color[1] = p_color[1];
2712 label.color[2] = p_color[2];
2713 label.color[3] = p_color[3];
2714 CmdInsertDebugUtilsLabelEXT(p_command_buffer, &label);
2715}
2716
2717void VulkanContext::command_end_label(VkCommandBuffer p_command_buffer) {
2718 if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
2719 return;
2720 }
2721 CmdEndDebugUtilsLabelEXT(p_command_buffer);
2722}
2723
2724void VulkanContext::set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name) {
2725 if (!is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
2726 return;
2727 }
2728 CharString obj_data = p_object_name.utf8();
2729 VkDebugUtilsObjectNameInfoEXT name_info;
2730 name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
2731 name_info.pNext = nullptr;
2732 name_info.objectType = p_object_type;
2733 name_info.objectHandle = p_object_handle;
2734 name_info.pObjectName = obj_data.get_data();
2735 SetDebugUtilsObjectNameEXT(device, &name_info);
2736}
2737
2738String VulkanContext::get_device_vendor_name() const {
2739 return device_vendor;
2740}
2741
2742String VulkanContext::get_device_name() const {
2743 return device_name;
2744}
2745
2746RenderingDevice::DeviceType VulkanContext::get_device_type() const {
2747 return RenderingDevice::DeviceType(device_type);
2748}
2749
2750String VulkanContext::get_device_api_version() const {
2751 return vformat("%d.%d.%d", VK_API_VERSION_MAJOR(device_api_version), VK_API_VERSION_MINOR(device_api_version), VK_API_VERSION_PATCH(device_api_version));
2752}
2753
2754String VulkanContext::get_device_pipeline_cache_uuid() const {
2755 return pipeline_cache_id;
2756}
2757
2758DisplayServer::VSyncMode VulkanContext::get_vsync_mode(DisplayServer::WindowID p_window) const {
2759 ERR_FAIL_COND_V_MSG(!windows.has(p_window), DisplayServer::VSYNC_ENABLED, "Could not get V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
2760 return windows[p_window].vsync_mode;
2761}
2762
2763void VulkanContext::set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) {
2764 ERR_FAIL_COND_MSG(!windows.has(p_window), "Could not set V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
2765 windows[p_window].vsync_mode = p_mode;
2766 _update_swap_chain(&windows[p_window]);
2767}
2768
2769VulkanContext::VulkanContext() {
2770 command_buffer_queue.resize(1); // First one is always the setup command.
2771 command_buffer_queue.write[0] = nullptr;
2772}
2773
2774VulkanContext::~VulkanContext() {
2775 if (queue_props) {
2776 free(queue_props);
2777 }
2778 if (device_initialized) {
2779 for (uint32_t i = 0; i < FRAME_LAG; i++) {
2780 vkDestroyFence(device, fences[i], nullptr);
2781 vkDestroySemaphore(device, draw_complete_semaphores[i], nullptr);
2782 if (separate_present_queue) {
2783 vkDestroySemaphore(device, image_ownership_semaphores[i], nullptr);
2784 }
2785 }
2786 if (inst_initialized && is_instance_extension_enabled(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
2787 DestroyDebugUtilsMessengerEXT(inst, dbg_messenger, nullptr);
2788 }
2789 if (inst_initialized && dbg_debug_report != VK_NULL_HANDLE) {
2790 DestroyDebugReportCallbackEXT(inst, dbg_debug_report, nullptr);
2791 }
2792 vkDestroyDevice(device, nullptr);
2793 }
2794 if (inst_initialized) {
2795 vkDestroyInstance(inst, nullptr);
2796 }
2797}
2798