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