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