quick backup - everything is going to be changed on vulkan side.
[demo] / src / vulkan / vk.cc
1 #define GLFW_INCLUDE_VULKAN
2 #include <GLFW/glfw3.h>
3
4 #include <alloca.h>
5 #include <stdio.h>
6 #include <string.h>
7
8 #include <string>
9 #include <vector>
10
11 #include "gfxapi.h"
12
13 /* global variables */
14 extern GLFWwindow *win;
15 extern int win_w;
16 extern int win_h;
17
18 /* static variables */
19 static std::vector<std::string> enabled_extension_names;
20 static VkInstance inst;
21 static VkDevice device;
22 static VkPhysicalDevice pdev;
23 static VkSurfaceKHR surface;
24 static uint32_t device_mem_idx;
25 static uint32_t num_queues;
26 static uint32_t qfamily_idx;
27
28 static const char *print_vulkan_error(VkResult error);
29 static const char *dev_type_str(VkPhysicalDeviceType type);
30 static const char *heap_flags_str(VkMemoryHeapFlags flags);
31 static const char *memtype_flags_str(VkMemoryPropertyFlags flags);
32 static const char *queue_flags_str(VkQueueFlags flags);
33
34 /* static fumctions */
35 static bool create_instance();
36 static bool create_device();
37
38 bool init_vulkan()
39 {
40         if(!glfwInit()) {
41                 fprintf(stderr, "Failed to initialize GLFW.\n");
42                 return false;
43         }
44
45         if(!glfwVulkanSupported()) {
46                 fprintf(stderr, "No Vulkan support on the device.\n");
47                 return false;
48         }
49
50         if(!create_instance()) {
51                 fprintf(stderr, "Failed to enable validation.\n");
52                 return false;
53         }
54
55         if(!glfwGetPhysicalDevicePresentationSupport(inst, pdev, qfamily_idx)) {
56                 fprintf(stderr, "Presentation support not found.\n");
57                 return false;
58         }
59
60         glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
61         if(!(win = glfwCreateWindow(win_w, win_h, "vkcow", 0, 0))) {
62                 fprintf(stderr, "Failed to create window.\n");
63                 return false;
64         }
65
66         if(VkResult err = glfwCreateWindowSurface(inst, win, 0, &surface)) {
67                 fprintf(stderr, "Failed to create KHR surface: %s\n", print_vulkan_error(err));
68                 return false;
69         }
70
71         return true;
72 }
73
74 void cleanup_vulkan()
75 {
76         //TODOs according to the book:
77         // 1- make sure all threads have been terminated (when I add threads)
78         // 2- destroy objects in *reverse* order
79
80         vkDestroySurfaceKHR(inst, surface, 0);
81
82         if(vkDeviceWaitIdle(device) == VK_SUCCESS) {
83                 vkDestroyDevice(device, 0);
84                 vkDestroyInstance(inst, 0);
85         }
86 }
87
88 static bool create_instance()
89 {
90         /* enable layers */
91         uint32_t layer_count = 0;
92         std::vector<const char *> enabled_layers;
93
94         if(vkEnumerateInstanceLayerProperties(&layer_count, 0) != VK_SUCCESS) {
95                 fprintf(stderr, "Failed to query layer properties.\n");
96                 return false;
97         }
98
99         if(layer_count > 0) {
100                 VkLayerProperties *layers = (VkLayerProperties *)alloca(layer_count * sizeof *layers);
101                 vkEnumerateInstanceLayerProperties(&layer_count, layers);
102                 for(uint32_t i=0; i<layer_count; i++) {
103                         if(strcmp(layers[i].layerName, "VK_LAYER_LUNARG_standard_validation")) {
104                                 enabled_layers.push_back(layers[i].layerName);
105                         }
106                 }
107         }
108
109         /* enable extensions */
110         uint32_t extensions_count = 0;
111         std::vector<const char *> enabled_extensions;
112
113         if(vkEnumerateInstanceExtensionProperties(0, &extensions_count, 0) != VK_SUCCESS) {
114                 fprintf(stderr, "Failed to enumerate instance extension properties\n");
115                 return false;
116         }
117
118         if(extensions_count > 0) {
119                 VkExtensionProperties *extensions = (VkExtensionProperties *)alloca(extensions_count * sizeof *extensions);
120                 vkEnumerateInstanceExtensionProperties(0, &extensions_count, extensions);
121
122                 for(uint32_t i=0; i<extensions_count; i++) {
123                         printf("Extension %u: %s %u.\n", i, extensions[i].extensionName, extensions[i].specVersion);
124                         //enable all the available extensions
125                         enabled_extensions.push_back(extensions[i].extensionName);
126                         enabled_extension_names.push_back(std::string(extensions[i].extensionName));
127                 }
128         }
129
130         /* create instance */
131         VkInstanceCreateInfo create_info;
132         memset(&create_info, 0, sizeof create_info);
133         create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
134
135         if(!enabled_layers.empty()) {
136                 create_info.enabledLayerCount = enabled_layers.size();
137                 create_info.ppEnabledLayerNames = enabled_layers.data();
138         }
139
140         if(!enabled_extensions.empty()) {
141                 create_info.enabledExtensionCount = enabled_extensions.size();
142                 create_info.ppEnabledExtensionNames = enabled_extensions.data();
143         }
144
145         if(vkCreateInstance(&create_info, 0, &inst) != VK_SUCCESS) {
146                 fprintf(stderr, "Failed to create instance.\n");
147                 return false;
148         }
149
150         if(!create_device())
151                 return false;
152
153         return true;
154 }
155
156 static bool create_device()
157 {
158         int qfam_idx = -1;
159         int pdev_idx = -1;
160
161         uint32_t dev_count;
162         if(vkEnumeratePhysicalDevices(inst, &dev_count, 0) != VK_SUCCESS) {
163                 fprintf(stderr, "Failed to enumerate physical devices.\n");
164                 return false;
165         }
166         printf("%u devices found.\n", (unsigned int)dev_count);
167
168         VkPhysicalDevice *phys_dev = (VkPhysicalDevice *)alloca(dev_count * sizeof *phys_dev);
169         vkEnumeratePhysicalDevices(inst, &dev_count, phys_dev);
170         VkPhysicalDeviceMemoryProperties memprop;
171
172         for(uint32_t i=0; i<dev_count; i++) {
173                 VkPhysicalDeviceProperties dev_props;
174                 vkGetPhysicalDeviceProperties(phys_dev[i], &dev_props);
175
176                 //memory heaps:
177                 vkGetPhysicalDeviceMemoryProperties(phys_dev[i], &memprop);
178                 printf("\tNumber of heaps: %u\n", memprop.memoryHeapCount);
179                 for(uint32_t j=0; j<memprop.memoryHeapCount; j++) {
180                         printf("\t\tHeap %u size: %lu\n", j, (unsigned long)memprop.memoryHeaps[j].size);
181                         printf("\t\tHeap %u flags: %s\n", j, heap_flags_str(memprop.memoryHeaps[j].flags));
182                 }
183                 //memory types
184                 printf("\tMemory types: %u\n", memprop.memoryTypeCount);
185                 for(uint32_t j=0; j<memprop.memoryTypeCount; j++) {
186                         printf("\t\tType %u heap index: %u\n", j, memprop.memoryTypes[j].heapIndex);
187                         printf("\t\tType %u flags: %s\n", j, memtype_flags_str(memprop.memoryTypes[j].propertyFlags));
188                 }
189
190                 //supported features
191                 VkPhysicalDeviceFeatures features;
192                 vkGetPhysicalDeviceFeatures(phys_dev[i], &features);
193
194                 //queue families
195                 uint32_t qfam_count;
196                 vkGetPhysicalDeviceQueueFamilyProperties(phys_dev[i], &qfam_count, 0);
197                 printf("\tQueue Families: %u\n", qfam_count);
198                 VkQueueFamilyProperties *qfam_props = new VkQueueFamilyProperties[qfam_count];
199                 vkGetPhysicalDeviceQueueFamilyProperties(phys_dev[i], &qfam_count, qfam_props);
200                 for(uint32_t j=0; j<qfam_count; j++) {
201                         printf("\t\tFamily %u flags: %s\n", j, queue_flags_str(qfam_props[j].queueFlags));
202                         printf("\t\tFamily %u number of queues: %u\n", j, qfam_props[j].queueCount);
203
204                         if((qfam_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) && (pdev_idx == -1)) {
205                                 pdev_idx = i;
206                                 qfam_idx = j;
207                                 num_queues = qfam_props[j].queueCount;
208                         }
209                 }
210                 delete [] qfam_props;
211         }
212
213         if(pdev_idx == -1) {
214                 fprintf(stderr, "No suitable devices found.\n");
215                 return false;
216         }
217
218         pdev = *(phys_dev + pdev_idx);
219         qfamily_idx = qfam_idx;
220
221         /*      uint32_t layer_count;
222                 if(vkEnumerateDeviceLayerProperties(pdev, &layer_count, 0) != VK_SUCCESS) {
223                         fprintf(stderr, "Failed to enumerate device layers.\n");
224                         return false;
225                 }
226                 if(layer_count > 0) {
227                         VkLayerProperties *layers = (VkLayerProperties*)alloca(layer_count * sizeof *layers);
228                         vkEnumerateDeviceLayerProperties(pdev, &layer_count, layers);
229                         printf("%u layers found.\n", layer_count);
230                         for(uint32_t i=0; i<layer_count; i++) {
231                                 printf("Layer %u: %s (%u, %u)\n", i, layers[i].layerName,
232                                                 layers[i].specVersion, layers[i].implementationVersion);
233                                 printf("\tDesc: %s\n", layers[i].description);
234                         }
235                 }
236         */
237         VkDeviceCreateInfo dev_info;
238         memset(&dev_info, 0, sizeof dev_info);
239         dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
240
241         VkDeviceQueueCreateInfo dev_qinfo;
242         memset(&dev_qinfo, 0, sizeof dev_qinfo);
243         dev_qinfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
244         dev_qinfo.queueFamilyIndex = qfam_idx;
245         dev_qinfo.queueCount = 1;
246
247         dev_info.queueCreateInfoCount = 1;
248         dev_info.pQueueCreateInfos = &dev_qinfo;
249
250         if(vkCreateDevice(pdev, &dev_info, 0, &device) != VK_SUCCESS) {
251                 fprintf(stderr, "Failed to create logical device.\n");
252                 return false;
253         }
254
255         vkGetPhysicalDeviceMemoryProperties(pdev, &memprop);
256         for(uint32_t j=0; j<memprop.memoryTypeCount; j++) {
257                 if(memprop.memoryTypes[j].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
258                         device_mem_idx = j;
259                         printf("Selected device memory index: %u\n", device_mem_idx);
260                         break;
261                 }
262         }
263
264         return true;
265 }
266
267 static const char *print_vulkan_error(VkResult error)
268 {
269         std::string errmsg;
270         switch(error) {
271         case VK_SUCCESS:
272                 errmsg = std::string("VK_SUCCESS");
273                 break;
274         case VK_NOT_READY:
275                 errmsg = std::string("VK_NOT_READY");
276                 break;
277         case VK_TIMEOUT:
278                 errmsg = std::string("VK_TIMEOUT");
279                 break;
280         case VK_EVENT_SET:
281                 errmsg = std::string("VK_EVENT_SET");
282                 break;
283         case VK_EVENT_RESET:
284                 errmsg = std::string("VK_EVENT_RESET");
285                 break;
286         case VK_INCOMPLETE:
287                 errmsg = std::string("VK_EVENT");
288                 break;
289         case VK_ERROR_OUT_OF_HOST_MEMORY:
290                 errmsg = std::string("VK_ERROR_OUT_OF_HOST_MEMORY");
291                 break;
292         case VK_ERROR_OUT_OF_DEVICE_MEMORY:
293                 errmsg = std::string("VK_ERROR_OUT_OF_DEVICE_MEMORY");
294                 break;
295         case VK_ERROR_INITIALIZATION_FAILED:
296                 errmsg = std::string("VK_ERROR_INITIALIZATION_FAILED");
297                 break;
298         case VK_ERROR_DEVICE_LOST:
299                 errmsg = std::string("VK_ERROR_DEVICE_LOST");
300                 break;
301         case VK_ERROR_MEMORY_MAP_FAILED:
302                 errmsg = std::string("VK_ERROR_MEMORY_MAP_FAILED");
303                 break;
304         case VK_ERROR_LAYER_NOT_PRESENT:
305                 errmsg = std::string("VK_ERROR_LAYER_NOT_PRESENT");
306                 break;
307         case VK_ERROR_EXTENSION_NOT_PRESENT:
308                 errmsg = std::string("VK_ERROR_EXTENSION_NOT_PRESENT");
309                 break;
310         case VK_ERROR_FEATURE_NOT_PRESENT:
311                 errmsg = std::string("VK_ERROR_FEATURE_NOT_PRESENT");
312                 break;
313         case VK_ERROR_INCOMPATIBLE_DRIVER:
314                 errmsg = std::string("VK_ERROR_INCOMPATIBLE_DRIVER");
315                 break;
316         case VK_ERROR_TOO_MANY_OBJECTS:
317                 errmsg = std::string("VK_ERROR_TOO_MANY_OBJECTS");
318                 break;
319         case VK_ERROR_FORMAT_NOT_SUPPORTED:
320                 errmsg = std::string("VK_ERROR_FORMAT_NOT_SUPPORTED");
321                 break;
322         case VK_ERROR_FRAGMENTED_POOL:
323                 errmsg = std::string("VK_ERROR_FRAGMENTED_POOL");
324                 break;
325         default:
326                 errmsg = std::string("UNKNOWN");
327                 break;
328         }
329
330         return errmsg.c_str();
331 }
332
333 static const char *dev_type_str(VkPhysicalDeviceType type)
334 {
335         switch(type) {
336         case VK_PHYSICAL_DEVICE_TYPE_OTHER:
337                 return "other";
338         case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
339                 return "integrated GPU";
340         case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
341                 return "discrete GPU";
342         case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
343                 return "virtual GPU";
344         case VK_PHYSICAL_DEVICE_TYPE_CPU:
345                 return "CPU";
346         default:
347                 break;
348         }
349         return "unknown";
350 }
351
352 static const char *heap_flags_str(VkMemoryHeapFlags flags)
353 {
354         static std::string str;
355         str.clear();
356         if(flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
357                 str += "device-local ";
358         }
359         if(!str.empty())
360                 str.pop_back();
361         return str.c_str();
362 }
363
364 static const char *memtype_flags_str(VkMemoryPropertyFlags flags)
365 {
366         static std::string str;
367         str.clear();
368         if(flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
369                 str += "device-local ";
370         }
371         if(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
372                 str += "host-visible ";
373         }
374         if(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
375                 str += "host-coherent ";
376         }
377         if(flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
378                 str += "host-cached ";
379         }
380         if(flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
381                 str += "lazily-allocated ";
382         }
383         if(!str.empty())
384                 str.pop_back();
385         return str.c_str();
386 }
387
388 static const char *queue_flags_str(VkQueueFlags flags)
389 {
390         static std::string str;
391         str.clear();
392         if(flags & VK_QUEUE_GRAPHICS_BIT)
393                 str += "graphics ";
394         if(flags & VK_QUEUE_COMPUTE_BIT)
395                 str += "compute ";
396         if(flags & VK_QUEUE_TRANSFER_BIT)
397                 str += "transfer ";
398         if(flags & VK_QUEUE_SPARSE_BINDING_BIT)
399                 str += "sparse-binding ";
400         if(!str.empty())
401                 str.pop_back();
402         return str.c_str();
403 }