rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@0
|
3 #include <string.h>
|
nuclear@0
|
4 #include <alloca.h>
|
nuclear@0
|
5 #include <vulkan/vulkan.h>
|
nuclear@0
|
6
|
nuclear@0
|
7 const char *get_device_name(VkPhysicalDeviceType type);
|
nuclear@2
|
8 const char *get_mem_prop_flag_string(VkMemoryPropertyFlags flags);
|
nuclear@0
|
9 const char *get_queue_flag_string(VkQueueFlagBits flags);
|
nuclear@0
|
10 int ver_major(uint32_t ver);
|
nuclear@0
|
11 int ver_minor(uint32_t ver);
|
nuclear@0
|
12 int ver_patch(uint32_t ver);
|
nuclear@2
|
13 const char *mem_size_str(long sz);
|
nuclear@0
|
14
|
nuclear@0
|
15 int main(void)
|
nuclear@0
|
16 {
|
nuclear@0
|
17 int i, j;
|
nuclear@0
|
18 VkInstance vk;
|
nuclear@0
|
19 VkInstanceCreateInfo inst_info;
|
nuclear@0
|
20 VkPhysicalDevice *devices;
|
nuclear@0
|
21 VkDevice vkdev;
|
nuclear@0
|
22 VkDeviceCreateInfo dev_info;
|
nuclear@0
|
23 VkDeviceQueueCreateInfo queue_info;
|
nuclear@0
|
24 uint32_t num_devices;
|
nuclear@0
|
25 int sel_dev = -1;
|
nuclear@0
|
26 int sel_qfamily = -1;
|
nuclear@0
|
27 float qprio = 0.0f;
|
nuclear@0
|
28
|
nuclear@0
|
29 memset(&inst_info, 0, sizeof inst_info);
|
nuclear@0
|
30 inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
nuclear@0
|
31
|
nuclear@0
|
32 if(vkCreateInstance(&inst_info, 0, &vk) != 0) {
|
nuclear@0
|
33 fprintf(stderr, "failed to create vulkan instance\n");
|
nuclear@0
|
34 return 1;
|
nuclear@0
|
35 }
|
nuclear@0
|
36 printf("created vulkan instance\n");
|
nuclear@0
|
37
|
nuclear@0
|
38 if(vkEnumeratePhysicalDevices(vk, &num_devices, 0) != 0) {
|
nuclear@0
|
39 fprintf(stderr, "failed to enumerate vulkan physical devices\n");
|
nuclear@0
|
40 return 1;
|
nuclear@0
|
41 }
|
nuclear@0
|
42 devices = alloca(num_devices * sizeof *devices);
|
nuclear@0
|
43 if(vkEnumeratePhysicalDevices(vk, &num_devices, devices) != 0) {
|
nuclear@0
|
44 fprintf(stderr, "failed to enumerate vulkan physical devices\n");
|
nuclear@0
|
45 return 1;
|
nuclear@0
|
46 }
|
nuclear@0
|
47 printf("found %u physical device(s)\n", (unsigned int)num_devices);
|
nuclear@0
|
48
|
nuclear@0
|
49 for(i=0; i<(int)num_devices; i++) {
|
nuclear@0
|
50 VkPhysicalDeviceProperties dev_prop;
|
nuclear@2
|
51 VkPhysicalDeviceMemoryProperties mem_prop;
|
nuclear@0
|
52 VkQueueFamilyProperties *qprop;
|
nuclear@0
|
53 uint32_t qprop_count;
|
nuclear@0
|
54
|
nuclear@0
|
55 vkGetPhysicalDeviceProperties(devices[i], &dev_prop);
|
nuclear@0
|
56
|
nuclear@0
|
57 printf("Device %d: %s\n", i, dev_prop.deviceName);
|
nuclear@0
|
58 printf(" type: %s\n", get_device_name(dev_prop.deviceType));
|
nuclear@0
|
59 printf(" API version: %d.%d.%d\n", ver_major(dev_prop.apiVersion), ver_minor(dev_prop.apiVersion),
|
nuclear@0
|
60 ver_patch(dev_prop.apiVersion));
|
nuclear@0
|
61 printf(" driver version: %d.%d.%d\n", ver_major(dev_prop.driverVersion), ver_minor(dev_prop.driverVersion),
|
nuclear@0
|
62 ver_patch(dev_prop.driverVersion));
|
nuclear@0
|
63 printf(" vendor id: %x device id: %x\n", dev_prop.vendorID, dev_prop.deviceID);
|
nuclear@0
|
64
|
nuclear@2
|
65
|
nuclear@2
|
66 vkGetPhysicalDeviceMemoryProperties(devices[i], &mem_prop);
|
nuclear@2
|
67 printf(" %d memory heaps:\n", mem_prop.memoryHeapCount);
|
nuclear@2
|
68 for(j=0; j<mem_prop.memoryHeapCount; j++) {
|
nuclear@2
|
69 VkMemoryHeap heap = mem_prop.memoryHeaps[j];
|
nuclear@2
|
70 printf(" Heap %d - size: %s, flags: %s\n", j, mem_size_str(heap.size),
|
nuclear@2
|
71 heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT ? "device-local" : "-");
|
nuclear@2
|
72 }
|
nuclear@2
|
73 printf(" %d memory types:\n", mem_prop.memoryTypeCount);
|
nuclear@2
|
74 for(j=0; j<mem_prop.memoryTypeCount; j++) {
|
nuclear@2
|
75 VkMemoryType type = mem_prop.memoryTypes[j];
|
nuclear@2
|
76 printf(" Type %d - heap: %d, flags: %s\n", j, type.heapIndex,
|
nuclear@2
|
77 get_mem_prop_flag_string(type.propertyFlags));
|
nuclear@2
|
78 }
|
nuclear@2
|
79
|
nuclear@0
|
80 vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &qprop_count, 0);
|
nuclear@0
|
81 if(qprop_count <= 0) {
|
nuclear@0
|
82 continue;
|
nuclear@0
|
83 }
|
nuclear@0
|
84 qprop = malloc(qprop_count * sizeof *qprop);
|
nuclear@0
|
85 vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &qprop_count, qprop);
|
nuclear@0
|
86
|
nuclear@0
|
87 for(j=0; j<qprop_count; j++) {
|
nuclear@0
|
88 printf(" Queue family %d:\n", j);
|
nuclear@0
|
89 printf(" flags: %s\n", get_queue_flag_string(qprop[j].queueFlags));
|
nuclear@0
|
90 printf(" num queues: %u\n", qprop[j].queueCount);
|
nuclear@0
|
91
|
nuclear@0
|
92 if(qprop[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
nuclear@0
|
93 sel_dev = i;
|
nuclear@0
|
94 sel_qfamily = j;
|
nuclear@0
|
95 }
|
nuclear@0
|
96 }
|
nuclear@0
|
97 free(qprop);
|
nuclear@0
|
98 }
|
nuclear@0
|
99
|
nuclear@0
|
100 if(sel_dev < 0 || sel_qfamily < 0) {
|
nuclear@0
|
101 fprintf(stderr, "failed to find any device with a graphics-capable command queue\n");
|
nuclear@0
|
102 vkDestroyDevice(vkdev, 0);
|
nuclear@0
|
103 return 1;
|
nuclear@0
|
104 }
|
nuclear@0
|
105
|
nuclear@1
|
106 // create device & command queue
|
nuclear@0
|
107 memset(&queue_info, 0, sizeof queue_info);
|
nuclear@0
|
108 queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
nuclear@0
|
109 queue_info.queueFamilyIndex = sel_qfamily;
|
nuclear@0
|
110 queue_info.queueCount = 1;
|
nuclear@0
|
111 queue_info.pQueuePriorities = &qprio;
|
nuclear@0
|
112
|
nuclear@0
|
113 memset(&dev_info, 0, sizeof dev_info);
|
nuclear@0
|
114 dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
nuclear@0
|
115 dev_info.queueCreateInfoCount = 1;
|
nuclear@0
|
116 dev_info.pQueueCreateInfos = &queue_info;
|
nuclear@0
|
117
|
nuclear@0
|
118 if(vkCreateDevice(devices[sel_dev], &dev_info, 0, &vkdev) != 0) {
|
nuclear@0
|
119 fprintf(stderr, "failed to create device %d\n", sel_dev);
|
nuclear@0
|
120 return 1;
|
nuclear@0
|
121 }
|
nuclear@0
|
122 printf("created device %d\n", sel_dev);
|
nuclear@0
|
123
|
nuclear@0
|
124 vkDestroyDevice(vkdev, 0);
|
nuclear@0
|
125 vkDestroyInstance(vk, 0);
|
nuclear@0
|
126 return 0;
|
nuclear@0
|
127 }
|
nuclear@0
|
128
|
nuclear@0
|
129
|
nuclear@0
|
130 const char *get_device_name(VkPhysicalDeviceType type)
|
nuclear@0
|
131 {
|
nuclear@0
|
132 switch(type) {
|
nuclear@0
|
133 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
|
nuclear@0
|
134 return "integrated GPU";
|
nuclear@0
|
135 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
|
nuclear@0
|
136 return "discrete GPU";
|
nuclear@0
|
137 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
|
nuclear@0
|
138 return "virtual GPU";
|
nuclear@0
|
139 case VK_PHYSICAL_DEVICE_TYPE_CPU:
|
nuclear@0
|
140 return "CPU";
|
nuclear@0
|
141 default:
|
nuclear@0
|
142 break;
|
nuclear@0
|
143 }
|
nuclear@0
|
144 return "unknown";
|
nuclear@0
|
145 }
|
nuclear@0
|
146
|
nuclear@2
|
147 const char *get_mem_prop_flag_string(VkMemoryPropertyFlags flags)
|
nuclear@2
|
148 {
|
nuclear@2
|
149 static char str[128];
|
nuclear@2
|
150
|
nuclear@2
|
151 str[0] = 0;
|
nuclear@2
|
152 if(flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
|
nuclear@2
|
153 strcat(str, "device-local ");
|
nuclear@2
|
154 }
|
nuclear@2
|
155 if(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
|
nuclear@2
|
156 strcat(str, "host-visible ");
|
nuclear@2
|
157 }
|
nuclear@2
|
158 if(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
|
nuclear@2
|
159 strcat(str, "host-coherent ");
|
nuclear@2
|
160 }
|
nuclear@2
|
161 if(flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
|
nuclear@2
|
162 strcat(str, "host-cached ");
|
nuclear@2
|
163 }
|
nuclear@2
|
164 if(flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
|
nuclear@2
|
165 strcat(str, "lazily-allocated ");
|
nuclear@2
|
166 }
|
nuclear@2
|
167
|
nuclear@2
|
168 if(!*str) {
|
nuclear@2
|
169 strcat(str, "-");
|
nuclear@2
|
170 }
|
nuclear@2
|
171 return str;
|
nuclear@2
|
172 }
|
nuclear@2
|
173
|
nuclear@0
|
174 const char *get_queue_flag_string(VkQueueFlagBits flags)
|
nuclear@0
|
175 {
|
nuclear@0
|
176 static char str[128];
|
nuclear@0
|
177
|
nuclear@0
|
178 str[0] = 0;
|
nuclear@0
|
179 if(flags & VK_QUEUE_GRAPHICS_BIT) {
|
nuclear@0
|
180 strcat(str, "graphics ");
|
nuclear@0
|
181 }
|
nuclear@0
|
182 if(flags & VK_QUEUE_COMPUTE_BIT) {
|
nuclear@0
|
183 strcat(str, "compute ");
|
nuclear@0
|
184 }
|
nuclear@0
|
185 if(flags & VK_QUEUE_TRANSFER_BIT) {
|
nuclear@0
|
186 strcat(str, "transfer ");
|
nuclear@0
|
187 }
|
nuclear@0
|
188 if(flags & VK_QUEUE_SPARSE_BINDING_BIT) {
|
nuclear@0
|
189 strcat(str, "sparse-binding ");
|
nuclear@0
|
190 }
|
nuclear@2
|
191 if(!*str) {
|
nuclear@2
|
192 strcat(str, "-");
|
nuclear@2
|
193 }
|
nuclear@0
|
194 return str;
|
nuclear@0
|
195 }
|
nuclear@0
|
196
|
nuclear@0
|
197 int ver_major(uint32_t ver)
|
nuclear@0
|
198 {
|
nuclear@0
|
199 return (ver >> 22) & 0x3ff;
|
nuclear@0
|
200 }
|
nuclear@0
|
201
|
nuclear@0
|
202 int ver_minor(uint32_t ver)
|
nuclear@0
|
203 {
|
nuclear@0
|
204 return (ver >> 12) & 0x3ff;
|
nuclear@0
|
205 }
|
nuclear@0
|
206
|
nuclear@0
|
207 int ver_patch(uint32_t ver)
|
nuclear@0
|
208 {
|
nuclear@0
|
209 return ver & 0xfff;
|
nuclear@0
|
210 }
|
nuclear@2
|
211
|
nuclear@2
|
212 const char *mem_size_str(long sz)
|
nuclear@2
|
213 {
|
nuclear@2
|
214 static char str[64];
|
nuclear@2
|
215 static const char *unitstr[] = { "bytes", "KB", "MB", "GB", "TB", "PB", 0 };
|
nuclear@2
|
216 int uidx = 0;
|
nuclear@2
|
217 sz *= 10;
|
nuclear@2
|
218
|
nuclear@2
|
219 while(sz >= 10240 && unitstr[uidx + 1]) {
|
nuclear@2
|
220 sz /= 1024;
|
nuclear@2
|
221 ++uidx;
|
nuclear@2
|
222 }
|
nuclear@2
|
223 sprintf(str, "%ld.%ld %s", sz / 10, sz % 10, unitstr[uidx]);
|
nuclear@2
|
224 return str;
|
nuclear@2
|
225 }
|