1 /* Copyright (c) 2017-2020 Hans-Kristian Arntzen
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be
12  * included in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #pragma once
24 
25 #include "vulkan_headers.hpp"
26 #include "logging.hpp"
27 #include <memory>
28 #include <functional>
29 
30 namespace Vulkan
31 {
32 struct DeviceFeatures
33 {
34 	bool supports_physical_device_properties2 = false;
35 	bool supports_external = false;
36 	bool supports_dedicated = false;
37 	bool supports_image_format_list = false;
38 	bool supports_debug_marker = false;
39 	bool supports_debug_utils = false;
40 	bool supports_mirror_clamp_to_edge = false;
41 	bool supports_google_display_timing = false;
42 	bool supports_nv_device_diagnostic_checkpoints = false;
43 	bool supports_vulkan_11_instance = false;
44 	bool supports_vulkan_11_device = false;
45 	bool supports_external_memory_host = false;
46 	bool supports_surface_capabilities2 = false;
47 	bool supports_full_screen_exclusive = false;
48 	bool supports_update_template = false;
49 	bool supports_maintenance_1 = false;
50 	bool supports_maintenance_2 = false;
51 	bool supports_maintenance_3 = false;
52 	bool supports_descriptor_indexing = false;
53 	bool supports_conservative_rasterization = false;
54 	bool supports_bind_memory2 = false;
55 	bool supports_get_memory_requirements2 = false;
56 	bool supports_draw_indirect_count = false;
57 	bool supports_draw_parameters = false;
58 	bool supports_driver_properties = false;
59 	bool supports_calibrated_timestamps = false;
60 	VkPhysicalDeviceSubgroupProperties subgroup_properties = {};
61 	VkPhysicalDevice8BitStorageFeaturesKHR storage_8bit_features = {};
62 	VkPhysicalDevice16BitStorageFeaturesKHR storage_16bit_features = {};
63 	VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8_features = {};
64 	VkPhysicalDeviceFeatures enabled_features = {};
65 	VkPhysicalDeviceExternalMemoryHostPropertiesEXT host_memory_properties = {};
66 	VkPhysicalDeviceMultiviewFeaturesKHR multiview_features = {};
67 	VkPhysicalDeviceImagelessFramebufferFeaturesKHR imageless_features = {};
68 	VkPhysicalDeviceSubgroupSizeControlFeaturesEXT subgroup_size_control_features = {};
69 	VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroup_size_control_properties = {};
70 	VkPhysicalDeviceComputeShaderDerivativesFeaturesNV compute_shader_derivative_features = {};
71 	VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset_features = {};
72 	VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote_to_helper_invocation_features = {};
73 	VkPhysicalDeviceScalarBlockLayoutFeaturesEXT scalar_block_features = {};
74 	VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR ubo_std430_features = {};
75 	VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore_features = {};
76 	VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptor_indexing_features = {};
77 	VkPhysicalDeviceDescriptorIndexingPropertiesEXT descriptor_indexing_properties = {};
78 	VkPhysicalDeviceConservativeRasterizationPropertiesEXT conservative_rasterization_properties = {};
79 	VkPhysicalDevicePerformanceQueryFeaturesKHR performance_query_features = {};
80 	VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR sampler_ycbcr_conversion_features = {};
81 	VkPhysicalDeviceDriverPropertiesKHR driver_properties = {};
82 };
83 
84 enum VendorID
85 {
86 	VENDOR_ID_AMD = 0x1002,
87 	VENDOR_ID_NVIDIA = 0x10de,
88 	VENDOR_ID_INTEL = 0x8086,
89 	VENDOR_ID_ARM = 0x13b5,
90 	VENDOR_ID_QCOM = 0x5143
91 };
92 
93 enum ContextCreationFlagBits
94 {
95 	CONTEXT_CREATION_DISABLE_BINDLESS_BIT = 1 << 0
96 };
97 using ContextCreationFlags = uint32_t;
98 
99 class Context
100 {
101 public:
102 	bool init_instance_and_device(const char **instance_ext, uint32_t instance_ext_count, const char **device_ext, uint32_t device_ext_count,
103 	                              ContextCreationFlags flags = 0);
104 	bool init_from_instance_and_device(VkInstance instance, VkPhysicalDevice gpu, VkDevice device, VkQueue queue, uint32_t queue_family);
105 	bool init_device_from_instance(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface, const char **required_device_extensions,
106 	                               unsigned num_required_device_extensions, const char **required_device_layers,
107 	                               unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features,
108 	                               ContextCreationFlags flags = 0);
109 
110 	Context() = default;
111 	Context(const Context &) = delete;
112 	void operator=(const Context &) = delete;
113 	static bool init_loader(PFN_vkGetInstanceProcAddr addr);
114 
115 	~Context();
116 
get_instance() const117 	VkInstance get_instance() const
118 	{
119 		return instance;
120 	}
121 
get_gpu() const122 	VkPhysicalDevice get_gpu() const
123 	{
124 		return gpu;
125 	}
126 
get_device() const127 	VkDevice get_device() const
128 	{
129 		return device;
130 	}
131 
get_graphics_queue() const132 	VkQueue get_graphics_queue() const
133 	{
134 		return graphics_queue;
135 	}
136 
get_compute_queue() const137 	VkQueue get_compute_queue() const
138 	{
139 		return compute_queue;
140 	}
141 
get_transfer_queue() const142 	VkQueue get_transfer_queue() const
143 	{
144 		return transfer_queue;
145 	}
146 
get_gpu_props() const147 	const VkPhysicalDeviceProperties &get_gpu_props() const
148 	{
149 		return gpu_props;
150 	}
151 
get_mem_props() const152 	const VkPhysicalDeviceMemoryProperties &get_mem_props() const
153 	{
154 		return mem_props;
155 	}
156 
get_graphics_queue_family() const157 	uint32_t get_graphics_queue_family() const
158 	{
159 		return graphics_queue_family;
160 	}
161 
get_compute_queue_family() const162 	uint32_t get_compute_queue_family() const
163 	{
164 		return compute_queue_family;
165 	}
166 
get_transfer_queue_family() const167 	uint32_t get_transfer_queue_family() const
168 	{
169 		return transfer_queue_family;
170 	}
171 
get_timestamp_valid_bits() const172 	uint32_t get_timestamp_valid_bits() const
173 	{
174 		return timestamp_valid_bits;
175 	}
176 
release_instance()177 	void release_instance()
178 	{
179 		owned_instance = false;
180 	}
181 
release_device()182 	void release_device()
183 	{
184 		owned_device = false;
185 	}
186 
get_enabled_device_features() const187 	const DeviceFeatures &get_enabled_device_features() const
188 	{
189 		return ext;
190 	}
191 
192 	static const VkApplicationInfo &get_application_info(bool supports_vulkan_11);
193 
194 	void notify_validation_error(const char *msg);
195 	void set_notification_callback(std::function<void (const char *)> func);
196 
set_num_thread_indices(unsigned indices)197 	void set_num_thread_indices(unsigned indices)
198 	{
199 		num_thread_indices = indices;
200 	}
201 
get_num_thread_indices() const202 	unsigned get_num_thread_indices() const
203 	{
204 		return num_thread_indices;
205 	}
206 
get_device_table() const207 	const VolkDeviceTable &get_device_table() const
208 	{
209 		return device_table;
210 	}
211 
212 private:
213 	VkDevice device = VK_NULL_HANDLE;
214 	VkInstance instance = VK_NULL_HANDLE;
215 	VkPhysicalDevice gpu = VK_NULL_HANDLE;
216 	VolkDeviceTable device_table = {};
217 
218 	VkPhysicalDeviceProperties gpu_props = {};
219 	VkPhysicalDeviceMemoryProperties mem_props = {};
220 
221 	VkQueue graphics_queue = VK_NULL_HANDLE;
222 	VkQueue compute_queue = VK_NULL_HANDLE;
223 	VkQueue transfer_queue = VK_NULL_HANDLE;
224 	uint32_t graphics_queue_family = VK_QUEUE_FAMILY_IGNORED;
225 	uint32_t compute_queue_family = VK_QUEUE_FAMILY_IGNORED;
226 	uint32_t transfer_queue_family = VK_QUEUE_FAMILY_IGNORED;
227 	uint32_t timestamp_valid_bits = 0;
228 	unsigned num_thread_indices = 1;
229 
230 	bool create_instance(const char **instance_ext, uint32_t instance_ext_count);
231 	bool create_device(VkPhysicalDevice gpu, VkSurfaceKHR surface, const char **required_device_extensions,
232 	                   unsigned num_required_device_extensions, const char **required_device_layers,
233 	                   unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features,
234 	                   ContextCreationFlags flags);
235 
236 	bool owned_instance = false;
237 	bool owned_device = false;
238 	DeviceFeatures ext;
239 
240 #ifdef VULKAN_DEBUG
241 	VkDebugReportCallbackEXT debug_callback = VK_NULL_HANDLE;
242 	VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
243 #endif
244 	std::function<void (const char *)> message_callback;
245 
246 	void destroy();
247 	void check_descriptor_indexing_features();
248 	bool force_no_validation = false;
249 };
250 }
251