1 /* Copyright (c) 2017-2018 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 <volk.h>
26 
27 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
28 // Workaround silly Xlib headers that define macros for these globally :(
29 #undef None
30 #undef Bool
31 #endif
32 
33 #include "util.hpp"
34 #include <memory>
35 #include <stdexcept>
36 #include <functional>
37 #include "util.hpp"
38 
39 #define V_S(x) #x
40 #define V_S_(x) V_S(x)
41 #define S__LINE__ V_S_(__LINE__)
42 
43 #define V(x)                                                                                           \
44 	do                                                                                                 \
45 	{                                                                                                  \
46 		VkResult err = x;                                                                              \
47 		if (err != VK_SUCCESS && err != VK_INCOMPLETE)                                                 \
48 			throw std::runtime_error("Vulkan call failed at " __FILE__ ":" S__LINE__ ".\n"); \
49 	} while (0)
50 
51 #ifdef VULKAN_DEBUG
52 #define VK_ASSERT(x)                                             \
53 	do                                                           \
54 	{                                                            \
55 		if (!bool(x))                                            \
56 		{                                                        \
57 			LOGE("Vulkan error at %s:%d.\n", __FILE__, __LINE__); \
58 			std::abort();                                        \
59 		}                                                        \
60 	} while (0)
61 #else
62 #define VK_ASSERT(x) ((void)0)
63 #endif
64 
65 namespace Vulkan
66 {
67 struct NoCopyNoMove
68 {
69 	NoCopyNoMove() = default;
70 	NoCopyNoMove(const NoCopyNoMove &) = delete;
71 	void operator=(const NoCopyNoMove &) = delete;
72 };
73 }
74 
75 namespace Vulkan
76 {
77 struct DeviceFeatures
78 {
79 	bool supports_physical_device_properties2 = false;
80 	bool supports_external = false;
81 	bool supports_dedicated = false;
82 	bool supports_image_format_list = false;
83 	bool supports_debug_marker = false;
84 	bool supports_debug_utils = false;
85 	bool supports_mirror_clamp_to_edge = false;
86 	bool supports_google_display_timing = false;
87 	bool supports_vulkan_11_instance = false;
88 	bool supports_vulkan_11_device = false;
89 	VkPhysicalDeviceSubgroupProperties subgroup_properties = {};
90 	VkPhysicalDevice8BitStorageFeaturesKHR storage_8bit_features = {};
91 	VkPhysicalDevice16BitStorageFeaturesKHR storage_16bit_features = {};
92 	VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8_features = {};
93 	VkPhysicalDeviceFeatures enabled_features = {};
94 };
95 
96 enum VendorID
97 {
98 	VENDOR_ID_AMD = 0x1002,
99 	VENDOR_ID_NVIDIA = 0x10de,
100 	VENDOR_ID_INTEL = 0x8086,
101 	VENDOR_ID_ARM = 0x13b5
102 };
103 
104 class Context
105 {
106 public:
107 	Context(const char **instance_ext, uint32_t instance_ext_count, const char **device_ext, uint32_t device_ext_count);
108 	Context(VkInstance instance, VkPhysicalDevice gpu, VkDevice device, VkQueue queue, uint32_t queue_family);
109 	Context(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface, const char **required_device_extensions,
110 	        unsigned num_required_device_extensions, const char **required_device_layers,
111 	        unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features);
112 
113 	Context(const Context &) = delete;
114 	void operator=(const Context &) = delete;
115 	static bool init_loader(PFN_vkGetInstanceProcAddr addr);
116 
117 	~Context();
118 
get_instance() const119 	VkInstance get_instance() const
120 	{
121 		return instance;
122 	}
123 
get_gpu() const124 	VkPhysicalDevice get_gpu() const
125 	{
126 		return gpu;
127 	}
128 
get_device() const129 	VkDevice get_device() const
130 	{
131 		return device;
132 	}
133 
get_graphics_queue() const134 	VkQueue get_graphics_queue() const
135 	{
136 		return graphics_queue;
137 	}
138 
get_compute_queue() const139 	VkQueue get_compute_queue() const
140 	{
141 		return compute_queue;
142 	}
143 
get_transfer_queue() const144 	VkQueue get_transfer_queue() const
145 	{
146 		return transfer_queue;
147 	}
148 
get_gpu_props() const149 	const VkPhysicalDeviceProperties &get_gpu_props() const
150 	{
151 		return gpu_props;
152 	}
153 
get_mem_props() const154 	const VkPhysicalDeviceMemoryProperties &get_mem_props() const
155 	{
156 		return mem_props;
157 	}
158 
get_graphics_queue_family() const159 	uint32_t get_graphics_queue_family() const
160 	{
161 		return graphics_queue_family;
162 	}
163 
get_compute_queue_family() const164 	uint32_t get_compute_queue_family() const
165 	{
166 		return compute_queue_family;
167 	}
168 
get_transfer_queue_family() const169 	uint32_t get_transfer_queue_family() const
170 	{
171 		return transfer_queue_family;
172 	}
173 
release_instance()174 	void release_instance()
175 	{
176 		owned_instance = false;
177 	}
178 
release_device()179 	void release_device()
180 	{
181 		owned_device = false;
182 	}
183 
get_enabled_device_features() const184 	const DeviceFeatures &get_enabled_device_features() const
185 	{
186 		return ext;
187 	}
188 
189 	static const VkApplicationInfo &get_application_info(bool supports_vulkan_11);
190 
191 	void notify_validation_error(const char *msg);
192 	void set_notification_callback(std::function<void (const char *)> func);
193 
194 private:
195 	VkDevice device = VK_NULL_HANDLE;
196 	VkInstance instance = VK_NULL_HANDLE;
197 	VkPhysicalDevice gpu = VK_NULL_HANDLE;
198 
199 	VkPhysicalDeviceProperties gpu_props;
200 	VkPhysicalDeviceMemoryProperties mem_props;
201 
202 	VkQueue graphics_queue = VK_NULL_HANDLE;
203 	VkQueue compute_queue = VK_NULL_HANDLE;
204 	VkQueue transfer_queue = VK_NULL_HANDLE;
205 	uint32_t graphics_queue_family = VK_QUEUE_FAMILY_IGNORED;
206 	uint32_t compute_queue_family = VK_QUEUE_FAMILY_IGNORED;
207 	uint32_t transfer_queue_family = VK_QUEUE_FAMILY_IGNORED;
208 
209 	bool create_instance(const char **instance_ext, uint32_t instance_ext_count);
210 	bool create_device(VkPhysicalDevice gpu, VkSurfaceKHR surface, const char **required_device_extensions,
211 	                   unsigned num_required_device_extensions, const char **required_device_layers,
212 	                   unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features);
213 
214 	bool owned_instance = false;
215 	bool owned_device = false;
216 	DeviceFeatures ext;
217 
218 #ifdef VULKAN_DEBUG
219 	VkDebugReportCallbackEXT debug_callback = VK_NULL_HANDLE;
220 	VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
221 #endif
222 	std::function<void (const char *)> message_callback;
223 
224 	void destroy();
225 };
226 }
227