vulkan_test_simple

annotate src/main.c @ 1:d5a3f6912f4d

how the hell did this work?
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 12 Sep 2024 04:19:14 +0300
parents 8de4fe926882
children
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 <stdint.h>
nuclear@0 5 #include <errno.h>
nuclear@0 6 #include <alloca.h>
nuclear@0 7 #include <GLFW/glfw3.h>
nuclear@0 8
nuclear@0 9 void keyb(GLFWwindow *win, int key, int sc, int act, int mods);
nuclear@0 10 int init(void);
nuclear@0 11 void destroy(void);
nuclear@0 12 void draw(void);
nuclear@0 13
nuclear@0 14 GLFWwindow *win;
nuclear@0 15 int win_width = 800;
nuclear@0 16 int win_height = 600;
nuclear@0 17 int redraw_pending;
nuclear@0 18
nuclear@0 19 int main(void)
nuclear@0 20 {
nuclear@0 21 if(!glfwInit()) {
nuclear@0 22 fprintf(stderr, "glfw init failed\n");
nuclear@0 23 return 1;
nuclear@0 24 }
nuclear@0 25
nuclear@0 26 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
nuclear@0 27 win = glfwCreateWindow(win_width, win_height, "test", 0, 0);
nuclear@0 28 glfwSetKeyCallback(win, keyb);
nuclear@0 29
nuclear@0 30 if(init() == -1) {
nuclear@0 31 glfwDestroyWindow(win);
nuclear@0 32 glfwTerminate();
nuclear@0 33 return 1;
nuclear@0 34 }
nuclear@0 35
nuclear@0 36 redraw_pending = 1;
nuclear@0 37
nuclear@0 38 while(!glfwWindowShouldClose(win)) {
nuclear@0 39 glfwWaitEvents();
nuclear@0 40
nuclear@0 41 if(redraw_pending) {
nuclear@0 42 redraw_pending = 0;
nuclear@0 43 draw();
nuclear@0 44 }
nuclear@0 45 }
nuclear@0 46
nuclear@0 47 destroy();
nuclear@0 48 glfwDestroyWindow(win);
nuclear@0 49 glfwTerminate();
nuclear@0 50 return 0;
nuclear@0 51 }
nuclear@0 52
nuclear@0 53 void keyb(GLFWwindow *win, int key, int sc, int act, int mods)
nuclear@0 54 {
nuclear@0 55 if(act == GLFW_PRESS) {
nuclear@0 56 switch(key) {
nuclear@0 57 case GLFW_KEY_ESCAPE:
nuclear@0 58 glfwSetWindowShouldClose(win, 1);
nuclear@0 59 break;
nuclear@0 60 }
nuclear@0 61 }
nuclear@0 62 }
nuclear@0 63
nuclear@0 64 /* -------------------------------------------------------------- */
nuclear@0 65 int create_instance(void);
nuclear@0 66 int create_surface(void);
nuclear@0 67 int choose_phys_dev(void);
nuclear@0 68 int create_device(void);
nuclear@0 69 int create_swapchain(void);
nuclear@0 70 int create_imgviews(void);
nuclear@0 71 int create_rendpass(void);
nuclear@0 72 int create_pipeline(void);
nuclear@0 73 int create_framebuf(void);
nuclear@0 74 int create_cmdpool(void);
nuclear@0 75 int create_cmdbuf(void);
nuclear@0 76 int create_semaphores(void);
nuclear@0 77 VkShaderModule load_shader(const char *fname);
nuclear@0 78
nuclear@0 79 VkInstance vk;
nuclear@0 80 VkPhysicalDevice vkpdev;
nuclear@0 81 int vkqfam_idx = -1;
nuclear@0 82 VkDevice vkdev;
nuclear@0 83 VkQueue vkq;
nuclear@0 84 VkSurfaceKHR vksurf;
nuclear@0 85 VkSurfaceCapabilitiesKHR vksurf_caps;
nuclear@0 86 int vksurf_numfmt, vksurf_selfmt;
nuclear@0 87 VkSurfaceFormatKHR *vksurf_fmt;
nuclear@0 88 VkSwapchainKHR vksc;
nuclear@0 89 int vksc_numimg;
nuclear@0 90 VkImage *vksc_img;
nuclear@0 91 VkExtent2D vksc_extent;
nuclear@0 92 VkImageView *vksc_view;
nuclear@0 93 VkRenderPass vkrpass;
nuclear@0 94 VkPipelineLayout vkpipe_layout;
nuclear@0 95 VkPipeline vkpipe;
nuclear@0 96 VkFramebuffer *vksc_fb;
nuclear@0 97 VkCommandPool vkcmdpool;
nuclear@0 98 VkCommandBuffer *vksc_cmdbuf;
nuclear@0 99 VkSemaphore sem_gotimg, sem_drawdone;
nuclear@0 100
nuclear@0 101 int init(void)
nuclear@0 102 {
nuclear@0 103 if(create_instance() == -1) return -1;
nuclear@0 104 if(create_surface() == -1) return -1;
nuclear@0 105 if(choose_phys_dev() == -1) return -1;
nuclear@0 106 if(create_device() == -1) return -1;
nuclear@0 107 if(create_swapchain() == -1) return -1;
nuclear@0 108 if(create_imgviews() == -1) return -1;
nuclear@0 109 if(create_rendpass() == -1) return -1;
nuclear@0 110 if(create_pipeline() == -1) return -1;
nuclear@0 111 if(create_framebuf() == -1) return -1;
nuclear@0 112 if(create_cmdpool() == -1) return -1;
nuclear@0 113 if(create_cmdbuf() == -1) return -1;
nuclear@0 114 if(create_semaphores() == -1) return -1;
nuclear@0 115 return 0;
nuclear@0 116 }
nuclear@0 117
nuclear@0 118 void destroy(void)
nuclear@0 119 {
nuclear@0 120 int i;
nuclear@0 121
nuclear@0 122 if(sem_gotimg) vkDestroySemaphore(vkdev, sem_gotimg, 0);
nuclear@0 123 if(sem_drawdone) vkDestroySemaphore(vkdev, sem_drawdone, 0);
nuclear@0 124 if(vkcmdpool) vkDestroyCommandPool(vkdev, vkcmdpool, 0);
nuclear@0 125 if(vksc_fb) {
nuclear@0 126 for(i=0; i<vksc_numimg; i++) {
nuclear@0 127 vkDestroyFramebuffer(vkdev, vksc_fb[i], 0);
nuclear@0 128 }
nuclear@0 129 }
nuclear@0 130 if(vkpipe) vkDestroyPipeline(vkdev, vkpipe, 0);
nuclear@0 131 if(vkpipe_layout) vkDestroyPipelineLayout(vkdev, vkpipe_layout, 0);
nuclear@0 132 if(vkrpass) vkDestroyRenderPass(vkdev, vkrpass, 0);
nuclear@0 133 if(vksc_view) {
nuclear@0 134 for(i=0; i<vksc_numimg; i++) {
nuclear@0 135 vkDestroyImageView(vkdev, vksc_view[i], 0);
nuclear@0 136 }
nuclear@0 137 }
nuclear@0 138 if(vksc) vkDestroySwapchainKHR(vkdev, vksc, 0);
nuclear@0 139 if(vkdev) vkDestroyDevice(vkdev, 0);
nuclear@0 140 if(vksurf) vkDestroySurfaceKHR(vk, vksurf, 0);
nuclear@0 141 if(vk) vkDestroyInstance(vk, 0);
nuclear@0 142 }
nuclear@0 143
nuclear@0 144 void draw(void)
nuclear@0 145 {
nuclear@0 146 uint32_t img_idx;
nuclear@0 147 VkSubmitInfo submit;
nuclear@0 148 VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
nuclear@0 149 VkPresentInfoKHR pres;
nuclear@0 150
nuclear@0 151 vkAcquireNextImageKHR(vkdev, vksc, UINT64_MAX, sem_gotimg, 0, &img_idx);
nuclear@0 152
nuclear@0 153 memset(&submit, 0, sizeof submit);
nuclear@0 154 submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
nuclear@0 155 submit.waitSemaphoreCount = 1;
nuclear@0 156 submit.pWaitSemaphores = &sem_gotimg;
nuclear@0 157 submit.pWaitDstStageMask = &wait_stages;
nuclear@0 158 submit.commandBufferCount = 1;
nuclear@0 159 submit.pCommandBuffers = vksc_cmdbuf + img_idx;
nuclear@0 160 submit.signalSemaphoreCount = 1;
nuclear@0 161 submit.pSignalSemaphores = &sem_drawdone;
nuclear@0 162
nuclear@0 163 if(vkQueueSubmit(vkq, 1, &submit, 0) != 0) {
nuclear@0 164 fprintf(stderr, "failed to submit draw commands\n");
nuclear@0 165 abort();
nuclear@0 166 }
nuclear@0 167
nuclear@0 168 memset(&pres, 0, sizeof pres);
nuclear@0 169 pres.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
nuclear@0 170 pres.waitSemaphoreCount = 1;
nuclear@0 171 pres.pWaitSemaphores = &sem_drawdone;
nuclear@0 172 pres.swapchainCount = 1;
nuclear@0 173 pres.pSwapchains = &vksc;
nuclear@0 174 pres.pImageIndices = &img_idx;
nuclear@0 175
nuclear@0 176 vkQueuePresentKHR(vkq, &pres);
nuclear@0 177 }
nuclear@0 178
nuclear@0 179 int create_instance(void)
nuclear@0 180 {
nuclear@0 181 VkApplicationInfo appinf;
nuclear@0 182 VkInstanceCreateInfo iinf;
nuclear@0 183 uint32_t num_ext;
nuclear@0 184 const char **ext;
nuclear@0 185
nuclear@0 186 ext = glfwGetRequiredInstanceExtensions(&num_ext);
nuclear@0 187
nuclear@0 188 memset(&appinf, 0, sizeof appinf);
nuclear@0 189 appinf.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
nuclear@0 190 appinf.pApplicationName = "test";
nuclear@0 191 appinf.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
nuclear@0 192 appinf.pEngineName = "fuckoff";
nuclear@0 193 appinf.engineVersion = VK_MAKE_VERSION(1, 0, 0);
nuclear@0 194 appinf.apiVersion = VK_API_VERSION_1_0;
nuclear@0 195
nuclear@0 196 memset(&iinf, 0, sizeof iinf);
nuclear@0 197 iinf.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
nuclear@0 198 iinf.pApplicationInfo = &appinf;
nuclear@0 199 iinf.enabledExtensionCount = num_ext;
nuclear@0 200 iinf.ppEnabledExtensionNames = ext;
nuclear@0 201
nuclear@0 202 if(vkCreateInstance(&iinf, 0, &vk) != 0) {
nuclear@0 203 fprintf(stderr, "failed to create instance\n");
nuclear@0 204 return -1;
nuclear@0 205 }
nuclear@0 206 return 0;
nuclear@0 207 }
nuclear@0 208
nuclear@0 209 int create_surface(void)
nuclear@0 210 {
nuclear@0 211 if(glfwCreateWindowSurface(vk, win, 0, &vksurf) != 0) {
nuclear@0 212 fprintf(stderr, "failed to create window surface\n");
nuclear@0 213 return -1;
nuclear@0 214 }
nuclear@0 215 return 0;
nuclear@0 216 }
nuclear@0 217
nuclear@0 218 static int is_pdev_skookum(VkPhysicalDevice dev)
nuclear@0 219 {
nuclear@0 220 uint32_t i, num_fmt, num_qfam, num_ext;
nuclear@0 221 VkQueueFamilyProperties *qfam;
nuclear@0 222 VkExtensionProperties *ext;
nuclear@0 223 VkPhysicalDeviceProperties prop;
nuclear@0 224 VkPhysicalDeviceFeatures feat;
nuclear@0 225 VkBool32 can_pres;
nuclear@0 226 int have_swap_ext;
nuclear@0 227
nuclear@0 228 vkGetPhysicalDeviceProperties(dev, &prop);
nuclear@0 229 vkGetPhysicalDeviceFeatures(dev, &feat);
nuclear@0 230
nuclear@0 231 /* check if we have the swapchain extension */
nuclear@0 232 vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, 0);
nuclear@0 233 ext = alloca(num_ext * sizeof *ext);
nuclear@0 234 vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, ext);
nuclear@0 235
nuclear@0 236 have_swap_ext = 0;
nuclear@0 237 for(i=0; i<num_ext; i++) {
nuclear@0 238 if(strcmp(ext[i].extensionName, "VK_KHR_swapchain") == 0) {
nuclear@0 239 have_swap_ext = 1;
nuclear@0 240 break;
nuclear@0 241 }
nuclear@0 242 }
nuclear@0 243 if(!have_swap_ext) {
nuclear@0 244 return 0;
nuclear@0 245 }
nuclear@0 246
nuclear@0 247 /* populate format and present modes arrays, and make sure we have some of each */
nuclear@0 248 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
nuclear@0 249 if(!num_fmt || !(vksurf_fmt = malloc(num_fmt * sizeof *vksurf_fmt))) {
nuclear@0 250 return 0;
nuclear@0 251 }
nuclear@0 252 vksurf_numfmt = num_fmt;
nuclear@0 253 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, vksurf_fmt);
nuclear@0 254
nuclear@0 255 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
nuclear@0 256
nuclear@0 257 /* find a queue family which can do graphics and can present */
nuclear@0 258 vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, 0);
nuclear@0 259 qfam = alloca(num_qfam * sizeof *qfam);
nuclear@0 260 vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, qfam);
nuclear@0 261
nuclear@0 262 vkqfam_idx = -1;
nuclear@0 263 for(i=0; i<num_qfam; i++) {
nuclear@0 264 vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, vksurf, &can_pres);
nuclear@0 265 if(qfam[i].queueCount && (qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && can_pres) {
nuclear@0 266 vkqfam_idx = i;
nuclear@0 267 return 1;
nuclear@0 268 }
nuclear@0 269 }
nuclear@0 270
nuclear@0 271 free(vksurf_fmt);
nuclear@0 272 vksurf_fmt = 0;
nuclear@0 273 vksurf_numfmt = 0;
nuclear@0 274 return 0;
nuclear@0 275 }
nuclear@0 276
nuclear@0 277 static int choose_pixfmt(void)
nuclear@0 278 {
nuclear@0 279 int i, j;
nuclear@0 280 static const VkFormat pref[] = {
nuclear@0 281 VK_FORMAT_B8G8R8_UNORM,
nuclear@0 282 VK_FORMAT_R8G8B8_UNORM,
nuclear@0 283 VK_FORMAT_B8G8R8A8_UNORM,
nuclear@0 284 VK_FORMAT_R8G8B8A8_UNORM
nuclear@0 285 };
nuclear@0 286
nuclear@0 287 vksurf_selfmt = 0;
nuclear@0 288 for(i=0; i<vksurf_numfmt; i++) {
nuclear@0 289 if(vksurf_fmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
nuclear@0 290 continue;
nuclear@0 291 }
nuclear@0 292 for(j=0; j<sizeof pref / sizeof *pref; j++) {
nuclear@0 293 if(vksurf_fmt[i].format == pref[j]) {
nuclear@0 294 vksurf_selfmt = i;
nuclear@0 295 return i;
nuclear@0 296 }
nuclear@0 297 }
nuclear@0 298 }
nuclear@0 299 return -1;
nuclear@0 300 }
nuclear@0 301
nuclear@0 302 int choose_phys_dev(void)
nuclear@0 303 {
nuclear@0 304 uint32_t i, num_pdev;
nuclear@0 305 VkPhysicalDevice *pdev;
nuclear@0 306
nuclear@0 307 vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
nuclear@0 308 if(!num_pdev) {
nuclear@0 309 fprintf(stderr, "no vulkan devices found\n");
nuclear@0 310 return -1;
nuclear@0 311 }
nuclear@0 312 pdev = alloca(num_pdev * sizeof *pdev);
nuclear@0 313 vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
nuclear@0 314
nuclear@0 315 for(i=0; i<num_pdev; i++) {
nuclear@0 316 if(is_pdev_skookum(pdev[i])) {
nuclear@0 317 vkpdev = pdev[i];
nuclear@0 318 break;
nuclear@0 319 }
nuclear@0 320 }
nuclear@0 321 if(!vkpdev) {
nuclear@0 322 fprintf(stderr, "no skookum device found, vulkan can't chooch\n");
nuclear@0 323 return -1;
nuclear@0 324 }
nuclear@0 325
nuclear@0 326 choose_pixfmt();
nuclear@0 327 return 0;
nuclear@0 328 }
nuclear@0 329
nuclear@0 330 int create_device(void)
nuclear@0 331 {
nuclear@0 332 static const float prio = 1.0f;
nuclear@0 333 VkDeviceQueueCreateInfo qinf;
nuclear@0 334 VkPhysicalDeviceFeatures feat;
nuclear@0 335 VkDeviceCreateInfo devinf;
nuclear@0 336
nuclear@0 337 static const char *extensions[] = {
nuclear@0 338 "VK_KHR_swapchain"
nuclear@0 339 };
nuclear@0 340
nuclear@0 341 memset(&feat, 0, sizeof feat);
nuclear@0 342
nuclear@0 343 memset(&qinf, 0, sizeof qinf);
nuclear@0 344 qinf.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
nuclear@0 345 qinf.queueFamilyIndex = vkqfam_idx;
nuclear@0 346 qinf.queueCount = 1;
nuclear@0 347 qinf.pQueuePriorities = &prio;
nuclear@0 348
nuclear@0 349 memset(&devinf, 0, sizeof devinf);
nuclear@0 350 devinf.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
nuclear@0 351 devinf.pQueueCreateInfos = &qinf;
nuclear@0 352 devinf.queueCreateInfoCount = 1;
nuclear@0 353 devinf.pEnabledFeatures = &feat;
nuclear@0 354 devinf.enabledExtensionCount = sizeof extensions / sizeof *extensions;
nuclear@0 355 devinf.ppEnabledExtensionNames = extensions;
nuclear@0 356
nuclear@0 357 if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
nuclear@0 358 fprintf(stderr, "failed to create vulkan device\n");
nuclear@0 359 return -1;
nuclear@0 360 }
nuclear@0 361
nuclear@0 362 vkGetDeviceQueue(vkdev, vkqfam_idx, 0, &vkq);
nuclear@0 363 return 0;
nuclear@0 364 }
nuclear@0 365
nuclear@0 366 int create_swapchain(void)
nuclear@0 367 {
nuclear@0 368 uint32_t num;
nuclear@0 369 VkSwapchainCreateInfoKHR scinf;
nuclear@0 370
nuclear@0 371 vksc_extent.width = win_width;
nuclear@0 372 vksc_extent.height = win_height;
nuclear@0 373
nuclear@0 374 memset(&scinf, 0, sizeof scinf);
nuclear@0 375 scinf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
nuclear@0 376 scinf.surface = vksurf;
nuclear@0 377 scinf.minImageCount = 2;
nuclear@0 378 scinf.imageFormat = vksurf_fmt[vksurf_selfmt].format;
nuclear@0 379 scinf.imageColorSpace = vksurf_fmt[vksurf_selfmt].colorSpace;
nuclear@0 380 scinf.imageExtent = vksc_extent;
nuclear@0 381 scinf.imageArrayLayers = 1;
nuclear@0 382 scinf.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
nuclear@0 383 scinf.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
nuclear@0 384 scinf.preTransform = vksurf_caps.currentTransform;
nuclear@0 385 scinf.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
nuclear@0 386 scinf.presentMode = VK_PRESENT_MODE_FIFO_KHR;
nuclear@0 387 scinf.clipped = VK_TRUE;
nuclear@0 388
nuclear@0 389 if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
nuclear@0 390 fprintf(stderr, "failed to create swapchain\n");
nuclear@0 391 return -1;
nuclear@0 392 }
nuclear@0 393
nuclear@0 394 vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
nuclear@0 395 if(!num || !(vksc_img = malloc(num * sizeof *vksc_img))) {
nuclear@0 396 fprintf(stderr, "failed to allocate swapchain image array (%d images)\n", vksc_numimg);
nuclear@0 397 return -1;
nuclear@0 398 }
nuclear@0 399 vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
nuclear@0 400 vksc_numimg = num;
nuclear@0 401
nuclear@0 402 return 0;
nuclear@0 403 }
nuclear@0 404
nuclear@0 405 int create_imgviews(void)
nuclear@0 406 {
nuclear@0 407 int i;
nuclear@0 408 VkImageViewCreateInfo ivinf;
nuclear@0 409
nuclear@0 410 if(!(vksc_view = malloc(vksc_numimg * sizeof *vksc_view))) {
nuclear@0 411 fprintf(stderr, "failed to allocate image view array (%d images)\n", vksc_numimg);
nuclear@0 412 return -1;
nuclear@0 413 }
nuclear@0 414
nuclear@0 415 for(i=0; i<vksc_numimg; i++) {
nuclear@0 416 memset(&ivinf, 0, sizeof ivinf);
nuclear@0 417 ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
nuclear@0 418 ivinf.image = vksc_img[i];
nuclear@0 419 ivinf.format = vksurf_fmt[vksurf_selfmt].format;
nuclear@0 420 ivinf.components.r = ivinf.components.g = ivinf.components.b =
nuclear@0 421 ivinf.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
nuclear@0 422 ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
nuclear@0 423 ivinf.subresourceRange.levelCount = 1;
nuclear@0 424 ivinf.subresourceRange.layerCount = 1;
nuclear@1 425 ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
nuclear@0 426
nuclear@0 427 if(vkCreateImageView(vkdev, &ivinf, 0, vksc_view + i) != 0) {
nuclear@0 428 fprintf(stderr, "failed to create image view for image %d\n", i);
nuclear@0 429 return -1;
nuclear@0 430 }
nuclear@0 431 }
nuclear@0 432 return 0;
nuclear@0 433 }
nuclear@0 434
nuclear@0 435 int create_rendpass(void)
nuclear@0 436 {
nuclear@0 437 VkAttachmentDescription cat;
nuclear@0 438 VkAttachmentReference catref;
nuclear@0 439 VkSubpassDescription subpass;
nuclear@0 440 VkRenderPassCreateInfo pinf;
nuclear@0 441 VkSubpassDependency dep;
nuclear@0 442
nuclear@0 443 memset(&cat, 0, sizeof cat);
nuclear@0 444 cat.format = vksurf_fmt[vksurf_selfmt].format;
nuclear@0 445 cat.samples = VK_SAMPLE_COUNT_1_BIT;
nuclear@0 446 cat.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
nuclear@0 447 cat.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
nuclear@0 448 cat.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
nuclear@0 449 cat.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
nuclear@0 450 cat.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
nuclear@0 451 cat.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
nuclear@0 452
nuclear@0 453 memset(&catref, 0, sizeof catref);
nuclear@0 454 catref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
nuclear@0 455
nuclear@0 456 memset(&subpass, 0, sizeof subpass);
nuclear@0 457 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
nuclear@0 458 subpass.colorAttachmentCount = 1;
nuclear@0 459 subpass.pColorAttachments = &catref;
nuclear@0 460
nuclear@0 461 memset(&dep, 0, sizeof dep);
nuclear@0 462 dep.srcSubpass = VK_SUBPASS_EXTERNAL;
nuclear@0 463 dep.dstSubpass = 0;
nuclear@0 464 dep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
nuclear@0 465 dep.srcAccessMask = 0;
nuclear@0 466 dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
nuclear@0 467 dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
nuclear@0 468
nuclear@0 469 memset(&pinf, 0, sizeof pinf);
nuclear@0 470 pinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
nuclear@0 471 pinf.attachmentCount = 1;
nuclear@0 472 pinf.pAttachments = &cat;
nuclear@0 473 pinf.subpassCount = 1;
nuclear@0 474 pinf.pSubpasses = &subpass;
nuclear@0 475 pinf.dependencyCount = 1;
nuclear@0 476 pinf.pDependencies = &dep;
nuclear@0 477
nuclear@0 478 if(vkCreateRenderPass(vkdev, &pinf, 0, &vkrpass) != 0) {
nuclear@0 479 fprintf(stderr, "failed to create render pass\n");
nuclear@0 480 return -1;
nuclear@0 481 }
nuclear@0 482 return 0;
nuclear@0 483 }
nuclear@0 484
nuclear@0 485 int create_pipeline(void)
nuclear@0 486 {
nuclear@0 487 int i;
nuclear@0 488 VkShaderModule sdr[2];
nuclear@0 489 VkPipelineShaderStageCreateInfo ssinf[2];
nuclear@0 490 VkPipelineVertexInputStateCreateInfo vinp;
nuclear@0 491 VkPipelineInputAssemblyStateCreateInfo vasm;
nuclear@0 492 VkViewport vport;
nuclear@0 493 VkRect2D scissor;
nuclear@0 494 VkPipelineViewportStateCreateInfo vp;
nuclear@0 495 VkPipelineRasterizationStateCreateInfo rast;
nuclear@0 496 VkPipelineMultisampleStateCreateInfo msaa;
nuclear@0 497 VkPipelineColorBlendAttachmentState bat;
nuclear@0 498 VkPipelineColorBlendStateCreateInfo blend;
nuclear@0 499 VkPipelineLayoutCreateInfo lay;
nuclear@0 500 VkGraphicsPipelineCreateInfo pinf;
nuclear@0 501
nuclear@1 502 if(!(sdr[0] = load_shader("vertex.spv")) || !(sdr[1] = load_shader("pixel.spv"))) {
nuclear@0 503 return -1;
nuclear@0 504 }
nuclear@0 505 memset(ssinf, 0, sizeof ssinf);
nuclear@0 506 for(i=0; i<2; i++) {
nuclear@0 507 ssinf[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
nuclear@0 508 ssinf[i].stage = i == 0 ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT;
nuclear@0 509 ssinf[i].module = sdr[i];
nuclear@0 510 ssinf[i].pName = "main";
nuclear@0 511 }
nuclear@0 512
nuclear@0 513 memset(&vinp, 0, sizeof vinp);
nuclear@0 514 vinp.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
nuclear@0 515
nuclear@0 516 memset(&vasm, 0, sizeof vasm);
nuclear@0 517 vasm.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
nuclear@0 518 vasm.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
nuclear@0 519
nuclear@0 520 vport.x = vport.y = 0;
nuclear@0 521 vport.width = vksc_extent.width;
nuclear@0 522 vport.height = vksc_extent.height;
nuclear@0 523 vport.minDepth = 0.0f;
nuclear@0 524 vport.maxDepth = 1.0f;
nuclear@0 525
nuclear@0 526 scissor.offset.x = scissor.offset.y = 0;
nuclear@0 527 scissor.extent = vksc_extent;
nuclear@0 528
nuclear@0 529 memset(&vp, 0, sizeof vp);
nuclear@0 530 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
nuclear@0 531 vp.viewportCount = 1;
nuclear@0 532 vp.pViewports = &vport;
nuclear@0 533 vp.scissorCount = 1;
nuclear@0 534 vp.pScissors = &scissor;
nuclear@0 535
nuclear@0 536 memset(&rast, 0, sizeof rast);
nuclear@0 537 rast.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
nuclear@0 538 rast.polygonMode = VK_POLYGON_MODE_FILL;
nuclear@0 539 rast.lineWidth = 1.0f;
nuclear@0 540 rast.cullMode = VK_CULL_MODE_BACK_BIT;
nuclear@0 541 rast.frontFace = VK_FRONT_FACE_CLOCKWISE;
nuclear@0 542
nuclear@0 543 memset(&msaa, 0, sizeof msaa);
nuclear@0 544 msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
nuclear@0 545 msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
nuclear@0 546 msaa.minSampleShading = 1.0f;
nuclear@0 547
nuclear@0 548 memset(&bat, 0, sizeof bat);
nuclear@0 549 bat.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
nuclear@0 550 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
nuclear@0 551
nuclear@0 552 memset(&blend, 0, sizeof blend);
nuclear@0 553 blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
nuclear@0 554 blend.attachmentCount = 1;
nuclear@0 555 blend.pAttachments = &bat;
nuclear@0 556
nuclear@0 557
nuclear@0 558 memset(&lay, 0, sizeof lay);
nuclear@0 559 lay.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
nuclear@0 560
nuclear@0 561 if(vkCreatePipelineLayout(vkdev, &lay, 0, &vkpipe_layout) != 0) {
nuclear@0 562 fprintf(stderr, "failed to create a pipeline layout\n");
nuclear@0 563 return -1;
nuclear@0 564 }
nuclear@0 565
nuclear@0 566 memset(&pinf, 0, sizeof pinf);
nuclear@0 567 pinf.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
nuclear@0 568 pinf.stageCount = 2;
nuclear@0 569 pinf.pStages = ssinf;
nuclear@0 570 pinf.pVertexInputState = &vinp;
nuclear@0 571 pinf.pInputAssemblyState = &vasm;
nuclear@0 572 pinf.pViewportState = &vp;
nuclear@0 573 pinf.pRasterizationState = &rast;
nuclear@0 574 pinf.pMultisampleState = &msaa;
nuclear@0 575 pinf.pColorBlendState = &blend;
nuclear@0 576 pinf.layout = vkpipe_layout;
nuclear@0 577 pinf.renderPass = vkrpass;
nuclear@0 578 pinf.basePipelineIndex = -1;
nuclear@0 579
nuclear@0 580 if(vkCreateGraphicsPipelines(vkdev, 0, 1, &pinf, 0, &vkpipe) != 0) {
nuclear@0 581 fprintf(stderr, "failed to create graphics pipeline\n");
nuclear@0 582 return -1;
nuclear@0 583 }
nuclear@0 584
nuclear@0 585 for(i=0; i<2; i++) {
nuclear@0 586 vkDestroyShaderModule(vkdev, sdr[i], 0);
nuclear@0 587 }
nuclear@0 588 return 0;
nuclear@0 589 }
nuclear@0 590
nuclear@0 591 int create_framebuf(void)
nuclear@0 592 {
nuclear@0 593 int i;
nuclear@0 594 VkFramebufferCreateInfo fbinf;
nuclear@0 595
nuclear@0 596 if(!(vksc_fb = malloc(vksc_numimg * sizeof *vksc_fb))) {
nuclear@0 597 fprintf(stderr, "failed to allocate array for swap chain framebuffers\n");
nuclear@0 598 return -1;
nuclear@0 599 }
nuclear@0 600
nuclear@0 601 for(i=0; i<vksc_numimg; i++) {
nuclear@0 602 memset(&fbinf, 0, sizeof fbinf);
nuclear@0 603 fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
nuclear@0 604 fbinf.renderPass = vkrpass;
nuclear@0 605 fbinf.attachmentCount = 1;
nuclear@0 606 fbinf.pAttachments = vksc_view + i;
nuclear@0 607 fbinf.width = vksc_extent.width;
nuclear@0 608 fbinf.height = vksc_extent.height;
nuclear@0 609 fbinf.layers = 1;
nuclear@0 610
nuclear@0 611 if(vkCreateFramebuffer(vkdev, &fbinf, 0, vksc_fb + i) != 0) {
nuclear@0 612 fprintf(stderr, "failed to create framebuffer\n");
nuclear@0 613 return -1;
nuclear@0 614 }
nuclear@0 615 }
nuclear@0 616
nuclear@0 617 return 0;
nuclear@0 618 }
nuclear@0 619
nuclear@0 620 int create_cmdpool(void)
nuclear@0 621 {
nuclear@0 622 VkCommandPoolCreateInfo cpinf;
nuclear@0 623
nuclear@0 624 memset(&cpinf, 0, sizeof cpinf);
nuclear@0 625 cpinf.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
nuclear@0 626 cpinf.queueFamilyIndex = vkqfam_idx;
nuclear@0 627
nuclear@0 628 if(vkCreateCommandPool(vkdev, &cpinf, 0, &vkcmdpool) != 0) {
nuclear@0 629 fprintf(stderr, "failed to create command pool\n");
nuclear@0 630 return -1;
nuclear@0 631 }
nuclear@0 632 return 0;
nuclear@0 633 }
nuclear@0 634
nuclear@0 635 int create_cmdbuf(void)
nuclear@0 636 {
nuclear@0 637 int i;
nuclear@0 638 VkCommandBufferAllocateInfo cbinf;
nuclear@0 639
nuclear@0 640 if(!(vksc_cmdbuf = malloc(vksc_numimg * sizeof *vksc_cmdbuf))) {
nuclear@0 641 fprintf(stderr, "failed to allocate array of command buffers\n");
nuclear@0 642 return -1;
nuclear@0 643 }
nuclear@0 644
nuclear@0 645 memset(&cbinf, 0, sizeof cbinf);
nuclear@0 646 cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
nuclear@0 647 cbinf.commandPool = vkcmdpool;
nuclear@0 648 cbinf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
nuclear@0 649 cbinf.commandBufferCount = vksc_numimg;
nuclear@0 650
nuclear@0 651 if(vkAllocateCommandBuffers(vkdev, &cbinf, vksc_cmdbuf) != 0) {
nuclear@0 652 fprintf(stderr, "failed to allocate command buffers\n");
nuclear@0 653 return -1;
nuclear@0 654 }
nuclear@0 655
nuclear@0 656 /* pre-record command buffers, because why the fuck not */
nuclear@0 657 for(i=0; i<vksc_numimg; i++) {
nuclear@0 658 VkCommandBufferBeginInfo cbegin;
nuclear@0 659 VkRenderPassBeginInfo rbegin;
nuclear@0 660 VkClearValue clear;
nuclear@0 661
nuclear@0 662 memset(&cbegin, 0, sizeof cbegin);
nuclear@0 663 cbegin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
nuclear@0 664 cbegin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
nuclear@0 665
nuclear@0 666 if(vkBeginCommandBuffer(vksc_cmdbuf[i], &cbegin) != 0) {
nuclear@0 667 fprintf(stderr, "failed to begin command buffer recording\n");
nuclear@0 668 return -1;
nuclear@0 669 }
nuclear@0 670
nuclear@0 671 clear.color.float32[0] = 0.2f;
nuclear@0 672 clear.color.float32[1] = 0.2f;
nuclear@0 673 clear.color.float32[2] = 0.2f;
nuclear@0 674 clear.color.float32[3] = 1.0f;
nuclear@0 675
nuclear@0 676 memset(&rbegin, 0, sizeof rbegin);
nuclear@0 677 rbegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
nuclear@0 678 rbegin.renderPass = vkrpass;
nuclear@0 679 rbegin.framebuffer = vksc_fb[i];
nuclear@0 680 rbegin.renderArea.extent = vksc_extent;
nuclear@0 681 rbegin.clearValueCount = 1;
nuclear@0 682 rbegin.pClearValues = &clear;
nuclear@0 683
nuclear@0 684 vkCmdBeginRenderPass(vksc_cmdbuf[i], &rbegin, VK_SUBPASS_CONTENTS_INLINE);
nuclear@0 685 vkCmdBindPipeline(vksc_cmdbuf[i], VK_PIPELINE_BIND_POINT_GRAPHICS, vkpipe);
nuclear@0 686 vkCmdDraw(vksc_cmdbuf[i], 3, 1, 0, 0);
nuclear@0 687 vkCmdEndRenderPass(vksc_cmdbuf[i]);
nuclear@0 688
nuclear@0 689 if(vkEndCommandBuffer(vksc_cmdbuf[i]) != 0) {
nuclear@0 690 fprintf(stderr, "failed to record command buffer\n");
nuclear@0 691 return -1;
nuclear@0 692 }
nuclear@0 693 }
nuclear@0 694 return 0;
nuclear@0 695 }
nuclear@0 696
nuclear@0 697 int create_semaphores(void)
nuclear@0 698 {
nuclear@0 699 VkSemaphoreCreateInfo sinf;
nuclear@0 700
nuclear@0 701 memset(&sinf, 0, sizeof sinf);
nuclear@0 702 sinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
nuclear@0 703
nuclear@0 704 if(vkCreateSemaphore(vkdev, &sinf, 0, &sem_gotimg) != 0) {
nuclear@0 705 fprintf(stderr, "failed to create semaphore\n");
nuclear@0 706 return -1;
nuclear@0 707 }
nuclear@0 708 if(vkCreateSemaphore(vkdev, &sinf, 0, &sem_drawdone) != 0) {
nuclear@0 709 fprintf(stderr, "failed to create semaphore\n");
nuclear@0 710 return -1;
nuclear@0 711 }
nuclear@0 712 return 0;
nuclear@0 713 }
nuclear@0 714
nuclear@0 715 VkShaderModule load_shader(const char *fname)
nuclear@0 716 {
nuclear@0 717 FILE *fp;
nuclear@0 718 long sz;
nuclear@0 719 void *buf;
nuclear@0 720 VkShaderModuleCreateInfo sinf;
nuclear@0 721 VkShaderModule sdr;
nuclear@0 722
nuclear@0 723 if(!(fp = fopen(fname, "rb"))) {
nuclear@0 724 fprintf(stderr, "failed to open shader: %s: %s\n", fname, strerror(errno));
nuclear@0 725 return 0;
nuclear@0 726 }
nuclear@0 727 fseek(fp, 0, SEEK_END);
nuclear@0 728 sz = ftell(fp);
nuclear@0 729 fseek(fp, 0, SEEK_SET);
nuclear@0 730
nuclear@0 731 buf = alloca(sz);
nuclear@0 732 if(fread(buf, 1, sz, fp) < sz) {
nuclear@0 733 fprintf(stderr, "unexpected EOF while reading shader: %s\n", fname);
nuclear@0 734 fclose(fp);
nuclear@0 735 return 0;
nuclear@0 736 }
nuclear@0 737 fclose(fp);
nuclear@0 738
nuclear@0 739 memset(&sinf, 0, sizeof sinf);
nuclear@0 740 sinf.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
nuclear@0 741 sinf.codeSize = sz;
nuclear@0 742 sinf.pCode = buf;
nuclear@0 743
nuclear@0 744 if(vkCreateShaderModule(vkdev, &sinf, 0, &sdr) != 0) {
nuclear@0 745 fprintf(stderr, "failed to create shader from %s\n", fname);
nuclear@0 746 return 0;
nuclear@0 747 }
nuclear@0 748 return sdr;
nuclear@0 749 }