summaryrefslogtreecommitdiff
path: root/drivers/vulkan/vulkan_context.h
blob: b2eb43975f9ca918e87c8ba0725792b4343ba99d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/*************************************************************************/
/*  vulkan_context.h                                                     */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#ifndef VULKAN_CONTEXT_H
#define VULKAN_CONTEXT_H

#include "core/error/error_list.h"
#include "core/os/mutex.h"
#include "core/string/ustring.h"
#include "core/templates/rb_map.h"
#include "core/templates/rid_owner.h"
#include "servers/display_server.h"
#include "servers/rendering/rendering_device.h"

#ifdef USE_VOLK
#include <volk.h>
#else
#include <vulkan/vulkan.h>
#endif

#include "vulkan_hooks.h"

class VulkanContext {
public:
	struct SubgroupCapabilities {
		uint32_t size;
		VkShaderStageFlags supportedStages;
		VkSubgroupFeatureFlags supportedOperations;
		VkBool32 quadOperationsInAllStages;

		uint32_t supported_stages_flags_rd() const;
		String supported_stages_desc() const;
		uint32_t supported_operations_flags_rd() const;
		String supported_operations_desc() const;
	};

	struct MultiviewCapabilities {
		bool is_supported;
		bool geometry_shader_is_supported;
		bool tessellation_shader_is_supported;
		uint32_t max_view_count;
		uint32_t max_instance_count;
	};

	struct VRSCapabilities {
		bool pipeline_vrs_supported; // We can specify our fragment rate on a pipeline level
		bool primitive_vrs_supported; // We can specify our fragment rate on each drawcall
		bool attachment_vrs_supported; // We can provide a density map attachment on our framebuffer

		Size2i min_texel_size;
		Size2i max_texel_size;
	};

	struct ShaderCapabilities {
		bool shader_float16_is_supported;
		bool shader_int8_is_supported;
	};

	struct StorageBufferCapabilities {
		bool storage_buffer_16_bit_access_is_supported;
		bool uniform_and_storage_buffer_16_bit_access_is_supported;
		bool storage_push_constant_16_is_supported;
		bool storage_input_output_16;
	};

private:
	enum {
		MAX_EXTENSIONS = 128,
		MAX_LAYERS = 64,
		FRAME_LAG = 2
	};

	static VulkanHooks *vulkan_hooks;
	VkInstance inst = VK_NULL_HANDLE;
	VkPhysicalDevice gpu = VK_NULL_HANDLE;
	VkPhysicalDeviceProperties gpu_props;
	uint32_t queue_family_count = 0;
	VkQueueFamilyProperties *queue_props = nullptr;
	VkDevice device = VK_NULL_HANDLE;
	bool device_initialized = false;
	bool inst_initialized = false;

	// Vulkan 1.0 doesn't return version info so we assume this by default until we know otherwise
	uint32_t vulkan_major = 1;
	uint32_t vulkan_minor = 0;
	uint32_t vulkan_patch = 0;
	SubgroupCapabilities subgroup_capabilities;
	MultiviewCapabilities multiview_capabilities;
	VRSCapabilities vrs_capabilities;
	ShaderCapabilities shader_capabilities;
	StorageBufferCapabilities storage_buffer_capabilities;

	String device_vendor;
	String device_name;
	VkPhysicalDeviceType device_type;
	String pipeline_cache_id;
	uint32_t device_api_version = 0;

	bool buffers_prepared = false;

	// Present queue.
	bool queues_initialized = false;
	uint32_t graphics_queue_family_index = UINT32_MAX;
	uint32_t present_queue_family_index = UINT32_MAX;
	bool separate_present_queue = false;
	VkQueue graphics_queue = VK_NULL_HANDLE;
	VkQueue present_queue = VK_NULL_HANDLE;
	VkColorSpaceKHR color_space;
	VkFormat format;
	VkSemaphore draw_complete_semaphores[FRAME_LAG];
	VkSemaphore image_ownership_semaphores[FRAME_LAG];
	int frame_index = 0;
	VkFence fences[FRAME_LAG];
	VkPhysicalDeviceMemoryProperties memory_properties;
	VkPhysicalDeviceFeatures physical_device_features;

	typedef struct {
		VkImage image;
		VkCommandBuffer graphics_to_present_cmd;
		VkImageView view;
		VkFramebuffer framebuffer;
	} SwapchainImageResources;

	struct Window {
		VkSurfaceKHR surface = VK_NULL_HANDLE;
		VkSwapchainKHR swapchain = VK_NULL_HANDLE;
		SwapchainImageResources *swapchain_image_resources = VK_NULL_HANDLE;
		VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
		VkSemaphore image_acquired_semaphores[FRAME_LAG];
		bool semaphore_acquired = false;
		uint32_t current_buffer = 0;
		int width = 0;
		int height = 0;
		DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
		VkCommandPool present_cmd_pool = VK_NULL_HANDLE; // For separate present queue.
		VkRenderPass render_pass = VK_NULL_HANDLE;
	};

	struct LocalDevice {
		bool waiting = false;
		VkDevice device = VK_NULL_HANDLE;
		VkQueue queue = VK_NULL_HANDLE;
	};

	RID_Owner<LocalDevice, true> local_device_owner;

	HashMap<DisplayServer::WindowID, Window> windows;
	uint32_t swapchainImageCount = 0;

	// Commands.

	bool prepared = false;

	Vector<VkCommandBuffer> command_buffer_queue;
	int command_buffer_count = 1;

	// Extensions.

	bool VK_KHR_incremental_present_enabled = true;
	bool VK_GOOGLE_display_timing_enabled = true;
	uint32_t enabled_extension_count = 0;
	const char *extension_names[MAX_EXTENSIONS];
	bool enabled_debug_utils = false;

	/**
	 * True if VK_EXT_debug_report extension is used. VK_EXT_debug_report is deprecated but it is
	 * still used if VK_EXT_debug_utils is not available.
	 */
	bool enabled_debug_report = false;

	PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT = nullptr;
	PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT = nullptr;
	PFN_vkSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT = nullptr;
	PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT = nullptr;
	PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT = nullptr;
	PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT = nullptr;
	PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT = nullptr;
	PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT = nullptr;
	PFN_vkDebugReportMessageEXT DebugReportMessageEXT = nullptr;
	PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT = nullptr;
	PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR = nullptr;
	PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR = nullptr;
	PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
	PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR = nullptr;
	PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR = nullptr;
	PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR = nullptr;
	PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR = nullptr;
	PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR = nullptr;
	PFN_vkQueuePresentKHR fpQueuePresentKHR = nullptr;
	PFN_vkGetRefreshCycleDurationGOOGLE fpGetRefreshCycleDurationGOOGLE = nullptr;
	PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE = nullptr;
	PFN_vkCreateRenderPass2KHR fpCreateRenderPass2KHR = nullptr;

	VkDebugUtilsMessengerEXT dbg_messenger = VK_NULL_HANDLE;
	VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE;

	Error _obtain_vulkan_version();
	Error _initialize_extensions();
	Error _check_capabilities();

	VkBool32 _check_layers(uint32_t check_count, const char *const *check_names, uint32_t layer_count, VkLayerProperties *layers);
	static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(
			VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
			VkDebugUtilsMessageTypeFlagsEXT messageType,
			const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
			void *pUserData);

	static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_report_callback(
			VkDebugReportFlagsEXT flags,
			VkDebugReportObjectTypeEXT objectType,
			uint64_t object,
			size_t location,
			int32_t messageCode,
			const char *pLayerPrefix,
			const char *pMessage,
			void *pUserData);

	Error _create_instance();

	Error _create_physical_device(VkSurfaceKHR p_surface);

	Error _initialize_queues(VkSurfaceKHR p_surface);

	Error _create_device();

	Error _clean_up_swap_chain(Window *window);

	Error _update_swap_chain(Window *window);

	Error _create_swap_chain();
	Error _create_semaphores();

protected:
	virtual const char *_get_platform_surface_extension() const = 0;

	virtual Error _window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height);

	virtual bool _use_validation_layers();

	Error _get_preferred_validation_layers(uint32_t *count, const char *const **names);

public:
	// Extension calls
	VkResult vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);

	uint32_t get_vulkan_major() const { return vulkan_major; };
	uint32_t get_vulkan_minor() const { return vulkan_minor; };
	SubgroupCapabilities get_subgroup_capabilities() const { return subgroup_capabilities; };
	MultiviewCapabilities get_multiview_capabilities() const { return multiview_capabilities; };
	VRSCapabilities get_vrs_capabilities() const { return vrs_capabilities; };
	ShaderCapabilities get_shader_capabilities() const { return shader_capabilities; };
	StorageBufferCapabilities get_storage_buffer_capabilities() const { return storage_buffer_capabilities; };

	VkDevice get_device();
	VkPhysicalDevice get_physical_device();
	VkInstance get_instance() { return inst; }
	int get_swapchain_image_count() const;
	VkQueue get_graphics_queue() const;
	uint32_t get_graphics_queue_family_index() const;

	static void set_vulkan_hooks(VulkanHooks *p_vulkan_hooks) { vulkan_hooks = p_vulkan_hooks; };

	void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
	int window_get_width(DisplayServer::WindowID p_window = 0);
	int window_get_height(DisplayServer::WindowID p_window = 0);
	bool window_is_valid_swapchain(DisplayServer::WindowID p_window = 0);
	void window_destroy(DisplayServer::WindowID p_window_id);
	VkFramebuffer window_get_framebuffer(DisplayServer::WindowID p_window = 0);
	VkRenderPass window_get_render_pass(DisplayServer::WindowID p_window = 0);

	RID local_device_create();
	VkDevice local_device_get_vk_device(RID p_local_device);
	void local_device_push_command_buffers(RID p_local_device, const VkCommandBuffer *p_buffers, int p_count);
	void local_device_sync(RID p_local_device);
	void local_device_free(RID p_local_device);

	VkFormat get_screen_format() const;
	VkPhysicalDeviceLimits get_device_limits() const;

	void set_setup_buffer(VkCommandBuffer p_command_buffer);
	void append_command_buffer(VkCommandBuffer p_command_buffer);
	void resize_notify();
	void flush(bool p_flush_setup = false, bool p_flush_pending = false);
	Error prepare_buffers();
	Error swap_buffers();
	Error initialize();

	void command_begin_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color);
	void command_insert_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color);
	void command_end_label(VkCommandBuffer p_command_buffer);
	void set_object_name(VkObjectType p_object_type, uint64_t p_object_handle, String p_object_name);

	String get_device_vendor_name() const;
	String get_device_name() const;
	RenderingDevice::DeviceType get_device_type() const;
	String get_device_api_version() const;
	String get_device_pipeline_cache_uuid() const;

	void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode);
	DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const;

	VulkanContext();
	virtual ~VulkanContext();
};

#endif // VULKAN_DEVICE_H