1/**************************************************************************/
2/* vulkan_context.h */
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#ifndef VULKAN_CONTEXT_H
32#define VULKAN_CONTEXT_H
33
34#include "core/error/error_list.h"
35#include "core/os/mutex.h"
36#include "core/string/ustring.h"
37#include "core/templates/hash_map.h"
38#include "core/templates/rb_map.h"
39#include "core/templates/rid_owner.h"
40#include "servers/display_server.h"
41#include "servers/rendering/rendering_device.h"
42
43#ifdef USE_VOLK
44#include <volk.h>
45#else
46#include <vulkan/vulkan.h>
47#endif
48
49#include "vulkan_hooks.h"
50
51class VulkanContext {
52public:
53 struct SubgroupCapabilities {
54 uint32_t size;
55 VkShaderStageFlags supportedStages;
56 VkSubgroupFeatureFlags supportedOperations;
57 VkBool32 quadOperationsInAllStages;
58
59 uint32_t supported_stages_flags_rd() const;
60 String supported_stages_desc() const;
61 uint32_t supported_operations_flags_rd() const;
62 String supported_operations_desc() const;
63 };
64
65 struct MultiviewCapabilities {
66 bool is_supported;
67 bool geometry_shader_is_supported;
68 bool tessellation_shader_is_supported;
69 uint32_t max_view_count;
70 uint32_t max_instance_count;
71 };
72
73 struct VRSCapabilities {
74 bool pipeline_vrs_supported; // We can specify our fragment rate on a pipeline level.
75 bool primitive_vrs_supported; // We can specify our fragment rate on each drawcall.
76 bool attachment_vrs_supported; // We can provide a density map attachment on our framebuffer.
77
78 Size2i min_texel_size;
79 Size2i max_texel_size;
80
81 Size2i texel_size; // The texel size we'll use
82 };
83
84 struct ShaderCapabilities {
85 bool shader_float16_is_supported;
86 bool shader_int8_is_supported;
87 };
88
89 struct StorageBufferCapabilities {
90 bool storage_buffer_16_bit_access_is_supported;
91 bool uniform_and_storage_buffer_16_bit_access_is_supported;
92 bool storage_push_constant_16_is_supported;
93 bool storage_input_output_16;
94 };
95
96private:
97 enum {
98 MAX_EXTENSIONS = 128,
99 MAX_LAYERS = 64,
100 FRAME_LAG = 2
101 };
102
103 static VulkanHooks *vulkan_hooks;
104 VkInstance inst = VK_NULL_HANDLE;
105 VkPhysicalDevice gpu = VK_NULL_HANDLE;
106 VkPhysicalDeviceProperties gpu_props;
107 uint32_t queue_family_count = 0;
108 VkQueueFamilyProperties *queue_props = nullptr;
109 VkDevice device = VK_NULL_HANDLE;
110 bool device_initialized = false;
111 bool inst_initialized = false;
112
113 uint32_t instance_api_version = VK_API_VERSION_1_0;
114 SubgroupCapabilities subgroup_capabilities;
115 MultiviewCapabilities multiview_capabilities;
116 VRSCapabilities vrs_capabilities;
117 ShaderCapabilities shader_capabilities;
118 StorageBufferCapabilities storage_buffer_capabilities;
119
120 String device_vendor;
121 String device_name;
122 VkPhysicalDeviceType device_type;
123 String pipeline_cache_id;
124 uint32_t device_api_version = 0;
125
126 bool buffers_prepared = false;
127
128 // Present queue.
129 bool queues_initialized = false;
130 uint32_t graphics_queue_family_index = UINT32_MAX;
131 uint32_t present_queue_family_index = UINT32_MAX;
132 bool separate_present_queue = false;
133 VkQueue graphics_queue = VK_NULL_HANDLE;
134 VkQueue present_queue = VK_NULL_HANDLE;
135 VkColorSpaceKHR color_space;
136 VkFormat format;
137 VkSemaphore draw_complete_semaphores[FRAME_LAG];
138 VkSemaphore image_ownership_semaphores[FRAME_LAG];
139 int frame_index = 0;
140 VkFence fences[FRAME_LAG];
141 VkPhysicalDeviceMemoryProperties memory_properties;
142 VkPhysicalDeviceFeatures physical_device_features;
143
144 typedef struct {
145 VkImage image;
146 VkCommandBuffer graphics_to_present_cmd;
147 VkImageView view;
148 VkFramebuffer framebuffer;
149 } SwapchainImageResources;
150
151 struct Window {
152 VkSurfaceKHR surface = VK_NULL_HANDLE;
153 VkSwapchainKHR swapchain = VK_NULL_HANDLE;
154 SwapchainImageResources *swapchain_image_resources = VK_NULL_HANDLE;
155 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
156 VkSemaphore image_acquired_semaphores[FRAME_LAG];
157 bool semaphore_acquired = false;
158 uint32_t current_buffer = 0;
159 int width = 0;
160 int height = 0;
161 DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
162 VkCommandPool present_cmd_pool = VK_NULL_HANDLE; // For separate present queue.
163 VkRenderPass render_pass = VK_NULL_HANDLE;
164 };
165
166 struct LocalDevice {
167 bool waiting = false;
168 VkDevice device = VK_NULL_HANDLE;
169 VkQueue queue = VK_NULL_HANDLE;
170 };
171
172 RID_Owner<LocalDevice, true> local_device_owner;
173
174 HashMap<DisplayServer::WindowID, Window> windows;
175 uint32_t swapchainImageCount = 0;
176
177 // Commands.
178
179 bool prepared = false;
180
181 Vector<VkCommandBuffer> command_buffer_queue;
182 int command_buffer_count = 1;
183
184 // Extensions.
185 static bool instance_extensions_initialized;
186 static HashMap<CharString, bool> requested_instance_extensions;
187 HashSet<CharString> enabled_instance_extension_names;
188
189 static bool device_extensions_initialized;
190 static HashMap<CharString, bool> requested_device_extensions;
191 HashSet<CharString> enabled_device_extension_names;
192 bool VK_KHR_incremental_present_enabled = true;
193 bool VK_GOOGLE_display_timing_enabled = true;
194
195 PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT = nullptr;
196 PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT = nullptr;
197 PFN_vkSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT = nullptr;
198 PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT = nullptr;
199 PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT = nullptr;
200 PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT = nullptr;
201 PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT = nullptr;
202 PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT = nullptr;
203 PFN_vkDebugReportMessageEXT DebugReportMessageEXT = nullptr;
204 PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT = nullptr;
205 PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR = nullptr;
206 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
207 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
208 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR = nullptr;
209 PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR = nullptr;
210 PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR = nullptr;
211 PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR = nullptr;
212 PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR = nullptr;
213 PFN_vkQueuePresentKHR fpQueuePresentKHR = nullptr;
214 PFN_vkGetRefreshCycleDurationGOOGLE fpGetRefreshCycleDurationGOOGLE = nullptr;
215 PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE = nullptr;
216 PFN_vkCreateRenderPass2KHR fpCreateRenderPass2KHR = nullptr;
217
218 VkDebugUtilsMessengerEXT dbg_messenger = VK_NULL_HANDLE;
219 VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE;
220
221 Error _obtain_vulkan_version();
222 Error _initialize_instance_extensions();
223 Error _initialize_device_extensions();
224 Error _check_capabilities();
225
226 VkBool32 _check_layers(uint32_t check_count, const char *const *check_names, uint32_t layer_count, VkLayerProperties *layers);
227 static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(
228 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
229 VkDebugUtilsMessageTypeFlagsEXT messageType,
230 const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
231 void *pUserData);
232
233 static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_report_callback(
234 VkDebugReportFlagsEXT flags,
235 VkDebugReportObjectTypeEXT objectType,
236 uint64_t object,
237 size_t location,
238 int32_t messageCode,
239 const char *pLayerPrefix,
240 const char *pMessage,
241 void *pUserData);
242
243 Error _create_instance();
244
245 Error _create_physical_device(VkSurfaceKHR p_surface);
246
247 Error _initialize_queues(VkSurfaceKHR p_surface);
248
249 Error _create_device();
250
251 Error _clean_up_swap_chain(Window *window);
252
253 Error _update_swap_chain(Window *window);
254
255 Error _create_swap_chain();
256 Error _create_semaphores();
257
258 Vector<VkAttachmentReference> _convert_VkAttachmentReference2(uint32_t p_count, const VkAttachmentReference2 *p_refs);
259
260protected:
261 virtual const char *_get_platform_surface_extension() const = 0;
262
263 virtual Error _window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height);
264
265 virtual bool _use_validation_layers();
266
267 Error _get_preferred_validation_layers(uint32_t *count, const char *const **names);
268
269 virtual VkExtent2D _compute_swapchain_extent(const VkSurfaceCapabilitiesKHR &p_surf_capabilities, int *p_window_width, int *p_window_height) const;
270
271public:
272 // Extension calls.
273 bool supports_renderpass2() const { return is_device_extension_enabled(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); }
274 VkResult vkCreateRenderPass2KHR(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass);
275
276 uint32_t get_vulkan_major() const { return VK_API_VERSION_MAJOR(device_api_version); };
277 uint32_t get_vulkan_minor() const { return VK_API_VERSION_MINOR(device_api_version); };
278 const SubgroupCapabilities &get_subgroup_capabilities() const { return subgroup_capabilities; };
279 const MultiviewCapabilities &get_multiview_capabilities() const { return multiview_capabilities; };
280 const VRSCapabilities &get_vrs_capabilities() const { return vrs_capabilities; };
281 const ShaderCapabilities &get_shader_capabilities() const { return shader_capabilities; };
282 const StorageBufferCapabilities &get_storage_buffer_capabilities() const { return storage_buffer_capabilities; };
283 const VkPhysicalDeviceFeatures &get_physical_device_features() const { return physical_device_features; };
284
285 VkDevice get_device();
286 VkPhysicalDevice get_physical_device();
287 VkInstance get_instance() { return inst; }
288 int get_swapchain_image_count() const;
289 VkQueue get_graphics_queue() const;
290 uint32_t get_graphics_queue_family_index() const;
291
292 static void set_vulkan_hooks(VulkanHooks *p_vulkan_hooks) { vulkan_hooks = p_vulkan_hooks; };
293
294 static void register_requested_instance_extension(const CharString &extension_name, bool p_required);
295 bool is_instance_extension_enabled(const CharString &extension_name) const {
296 return enabled_instance_extension_names.has(extension_name);
297 }
298
299 static void register_requested_device_extension(const CharString &extension_name, bool p_required);
300 bool is_device_extension_enabled(const CharString &extension_name) const {
301 return enabled_device_extension_names.has(extension_name);
302 }
303
304 void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
305 int window_get_width(DisplayServer::WindowID p_window = 0);
306 int window_get_height(DisplayServer::WindowID p_window = 0);
307 bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0);
308 void window_destroy(DisplayServer::WindowID p_window_id);
309 VkFramebuffer window_get_framebuffer(DisplayServer::WindowID p_window = 0);
310 VkRenderPass window_get_render_pass(DisplayServer::WindowID p_window = 0);
311
312 RID local_device_create();
313 VkDevice local_device_get_vk_device(RID p_local_device);
314 void local_device_push_command_buffers(RID p_local_device, const VkCommandBuffer *p_buffers, int p_count);
315 void local_device_sync(RID p_local_device);
316 void local_device_free(RID p_local_device);
317
318 VkFormat get_screen_format() const;
319 VkPhysicalDeviceLimits get_device_limits() const;
320
321 void set_setup_buffer(VkCommandBuffer p_command_buffer);
322 void append_command_buffer(VkCommandBuffer p_command_buffer);
323 void resize_notify();
324 void flush(bool p_flush_setup = false, bool p_flush_pending = false);
325 Error prepare_buffers();
326 Error swap_buffers();
327 Error initialize();
328
329 void command_begin_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color);
330 void command_insert_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color);
331 void command_end_label(VkCommandBuffer p_command_buffer);
332 void set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name);
333
334 String get_device_vendor_name() const;
335 String get_device_name() const;
336 RenderingDevice::DeviceType get_device_type() const;
337 String get_device_api_version() const;
338 String get_device_pipeline_cache_uuid() const;
339
340 void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode);
341 DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const;
342
343 VulkanContext();
344 virtual ~VulkanContext();
345};
346
347#endif // VULKAN_CONTEXT_H
348