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 | |
51 | class VulkanContext { |
52 | public: |
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 | |
96 | private: |
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 | |
260 | protected: |
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 | |
271 | public: |
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 | |