vkdemo.c (25458B)
1 #include "vkdemo.h" 2 3 #define MAX_FRAMES_IN_FLIGHT 2 4 5 static uint32_t vert_shader[] = 6 #include "shader.vert.spv.inc" 7 ; 8 9 static uint32_t frag_shader[] = 10 #include "shader.frag.spv.inc" 11 ; 12 13 static inline void * 14 vkdemo_memory_arena_alloc(struct vkdemo_memory_arena *self, uint64_t size, uint64_t align) 15 { 16 assert(align); 17 assert(align % 2 == 0); 18 19 uint64_t off = align - 1; 20 uint64_t mask = ~off; 21 22 uintptr_t aligned_len = (self->len + off) & mask; 23 if (self->cap < aligned_len + size) 24 return NULL; 25 26 void *aligned_ptr = (uint8_t *) self->ptr + aligned_len; 27 self->len = aligned_len; 28 29 return aligned_ptr; 30 } 31 32 struct vkdemo_state { 33 struct { 34 VkInstance instance; 35 VkSurfaceKHR surface; 36 37 VkPhysicalDevice physical_device; 38 VkDevice device; 39 40 VkQueue graphics_queue; 41 VkQueue present_queue; 42 43 VkSwapchainKHR swapchain; 44 VkFormat swapchain_image_format; 45 VkExtent2D swapchain_extent; 46 47 struct { 48 VkImage *ptr; 49 uint32_t len; 50 } swapchain_images; 51 52 struct { 53 VkImageView *ptr; 54 uint32_t len; 55 } swapchain_image_views; 56 57 struct { 58 VkFramebuffer *ptr; 59 uint32_t len; 60 } swapchain_framebuffers; 61 62 VkRenderPass render_pass; 63 VkPipelineLayout pipeline_layout; 64 VkPipeline pipeline; 65 66 VkCommandPool command_pool; 67 VkCommandBuffer command_buffers[MAX_FRAMES_IN_FLIGHT]; 68 69 struct { 70 VkSemaphore image_available[MAX_FRAMES_IN_FLIGHT]; 71 VkSemaphore render_finished[MAX_FRAMES_IN_FLIGHT]; 72 VkFence in_flight[MAX_FRAMES_IN_FLIGHT]; 73 } sync_objects; 74 75 uint32_t frame_index; 76 } vk; 77 }; 78 79 struct queue_family_indices { 80 uint32_t graphics_family; 81 bool has_graphics_family; 82 83 uint32_t present_family; 84 bool has_present_family; 85 }; 86 87 static struct queue_family_indices 88 get_device_queue_families(VkPhysicalDevice device, VkSurfaceKHR surface) 89 { 90 struct queue_family_indices result = {0}; 91 92 uint32_t queue_family_count; 93 vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, NULL); 94 95 VkQueueFamilyProperties *queue_families = _alloca(queue_family_count * sizeof *queue_families); 96 vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families); 97 98 for (uint32_t i = 0; i < queue_family_count; i++) { 99 if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { 100 result.has_graphics_family = true; 101 result.graphics_family = i; 102 } 103 104 VkBool32 present_support = false; 105 vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &present_support); 106 if (present_support) { 107 result.has_present_family = true; 108 result.present_family = i; 109 } 110 111 if (result.has_graphics_family && result.has_present_family) 112 break; 113 } 114 115 return result; 116 } 117 118 static bool 119 is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface, const char **device_extensions, uint32_t device_extensions_len) 120 { 121 struct queue_family_indices indices = get_device_queue_families(device, surface); 122 123 // NOTE: we require a device to have both graphics and present capability for its queue 124 if (!indices.has_graphics_family || !indices.has_present_family) 125 return false; 126 127 uint32_t extension_count; 128 vkEnumerateDeviceExtensionProperties(device, NULL, &extension_count, NULL); 129 130 VkExtensionProperties *extensions = _alloca(extension_count * sizeof *extensions); 131 vkEnumerateDeviceExtensionProperties(device, NULL, &extension_count, extensions); 132 133 for (uint32_t i = 0; i < device_extensions_len; i++) { 134 for (uint32_t j = 0; j < extension_count; j++) { 135 if (strcmp(device_extensions[i], extensions[j].extensionName) == 0) 136 goto extension_found; 137 } 138 139 // NOTE: device does not support a required extension 140 return false; 141 142 extension_found: 143 continue; 144 } 145 146 uint32_t format_count; 147 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &format_count, NULL); 148 if (!format_count) return false; 149 150 uint32_t present_mode_count; 151 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_mode_count, NULL); 152 if (!present_mode_count) return false; 153 154 return true; 155 } 156 157 static VkExtent2D 158 get_swapchain_extent(VkSurfaceCapabilitiesKHR *surface_caps, uint32_t width, uint32_t height) 159 { 160 if (surface_caps->currentExtent.width == UINT32_MAX && surface_caps->currentExtent.height == UINT32_MAX) { 161 return (VkExtent2D) { 162 .width = CLAMP(width, surface_caps->minImageExtent.width, surface_caps->maxImageExtent.width), 163 .height = CLAMP(height, surface_caps->minImageExtent.height, surface_caps->maxImageExtent.height), 164 }; 165 } else { 166 return surface_caps->currentExtent; 167 } 168 } 169 170 static VkSurfaceFormatKHR 171 get_swapchain_format(VkSurfaceFormatKHR *formats, uint64_t len) 172 { 173 for (uint64_t i = 0; i < len; i++) { 174 if (formats[i].format == VK_FORMAT_B8G8R8A8_SRGB && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) 175 return formats[i]; 176 } 177 178 return formats[0]; 179 } 180 181 static VkPresentModeKHR 182 get_swapchain_present_mode(VkPresentModeKHR *present_modes, uint64_t len) 183 { 184 for (uint64_t i = 0; i < len; i++) { 185 if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) 186 return present_modes[i]; 187 } 188 189 return VK_PRESENT_MODE_FIFO_KHR; 190 } 191 192 static bool 193 recreate_swapchain(struct vkdemo_memory *memory, struct vkdemo_state *state, uint32_t width, uint32_t height, VkSwapchainKHR old_swapchain) 194 { 195 struct queue_family_indices indices = get_device_queue_families(state->vk.physical_device, state->vk.surface); 196 assert(indices.has_graphics_family && indices.has_present_family); 197 198 VkSurfaceCapabilitiesKHR surface_caps; 199 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(state->vk.physical_device, state->vk.surface, &surface_caps); 200 201 uint32_t format_count; 202 vkGetPhysicalDeviceSurfaceFormatsKHR(state->vk.physical_device, state->vk.surface, &format_count, NULL); 203 204 assert(format_count); 205 VkSurfaceFormatKHR *formats = _alloca(format_count * sizeof *formats); 206 vkGetPhysicalDeviceSurfaceFormatsKHR(state->vk.physical_device, state->vk.surface, &format_count, formats); 207 208 uint32_t present_mode_count; 209 vkGetPhysicalDeviceSurfacePresentModesKHR(state->vk.physical_device, state->vk.surface, &present_mode_count, NULL); 210 211 assert(present_mode_count); 212 VkPresentModeKHR *present_modes = _alloca(present_mode_count * sizeof *present_modes); 213 vkGetPhysicalDeviceSurfacePresentModesKHR(state->vk.physical_device, state->vk.surface, &present_mode_count, present_modes); 214 215 VkExtent2D extent = get_swapchain_extent(&surface_caps, width, height); 216 VkSurfaceFormatKHR format = get_swapchain_format(formats, format_count); 217 VkPresentModeKHR present_mode = get_swapchain_present_mode(present_modes, present_mode_count); 218 219 uint32_t image_count = surface_caps.minImageCount + 1; 220 if (surface_caps.maxImageCount) 221 image_count = MIN(image_count, surface_caps.maxImageCount); 222 223 assert(indices.graphics_family == indices.present_family); 224 VkSwapchainCreateInfoKHR swapchain_info = { 225 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 226 .surface = state->vk.surface, 227 .minImageCount = image_count, 228 .imageFormat = format.format, 229 .imageColorSpace = format.colorSpace, 230 .imageExtent = extent, 231 .imageArrayLayers = 1, 232 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 233 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, 234 .preTransform = surface_caps.currentTransform, 235 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, 236 .presentMode = present_mode, 237 .clipped = VK_TRUE, 238 .oldSwapchain = old_swapchain, 239 }; 240 241 state->vk.swapchain_image_format = format.format; 242 state->vk.swapchain_extent = extent; 243 244 if (vkCreateSwapchainKHR(state->vk.device, &swapchain_info, NULL, &state->vk.swapchain) != VK_SUCCESS) 245 return false; 246 247 vkGetSwapchainImagesKHR(state->vk.device, state->vk.swapchain, &image_count, NULL); 248 249 state->vk.swapchain_images.len = state->vk.swapchain_image_views.len = state->vk.swapchain_framebuffers.len = image_count; 250 251 state->vk.swapchain_images.ptr = vkdemo_memory_arena_alloc(&memory->permanent, state->vk.swapchain_images.len * sizeof *state->vk.swapchain_images.ptr, alignof(VkImage)); 252 assert(state->vk.swapchain_images.ptr); 253 254 vkGetSwapchainImagesKHR(state->vk.device, state->vk.swapchain, &state->vk.swapchain_images.len, state->vk.swapchain_images.ptr); 255 256 state->vk.swapchain_image_views.ptr = vkdemo_memory_arena_alloc(&memory->permanent, state->vk.swapchain_image_views.len * sizeof *state->vk.swapchain_image_views.ptr, alignof(VkImageView)); 257 assert(state->vk.swapchain_image_views.ptr); 258 259 for (uint32_t i = 0; i < state->vk.swapchain_images.len; i++) { 260 VkImageViewCreateInfo image_view_info = { 261 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 262 .image = state->vk.swapchain_images.ptr[i], 263 .viewType = VK_IMAGE_VIEW_TYPE_2D, 264 .format = state->vk.swapchain_image_format, 265 .components.r = VK_COMPONENT_SWIZZLE_IDENTITY, 266 .components.g = VK_COMPONENT_SWIZZLE_IDENTITY, 267 .components.b = VK_COMPONENT_SWIZZLE_IDENTITY, 268 .components.a = VK_COMPONENT_SWIZZLE_IDENTITY, 269 .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 270 .subresourceRange.baseMipLevel = 0, 271 .subresourceRange.levelCount = 1, 272 .subresourceRange.baseArrayLayer = 0, 273 .subresourceRange.layerCount = 1, 274 }; 275 276 if (vkCreateImageView(state->vk.device, &image_view_info, NULL, &state->vk.swapchain_image_views.ptr[i]) != VK_SUCCESS) 277 return false; 278 } 279 280 VkAttachmentDescription color_attachment = { 281 .format = state->vk.swapchain_image_format, 282 .samples = VK_SAMPLE_COUNT_1_BIT, 283 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 284 .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 285 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 286 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 287 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 288 .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 289 }; 290 291 VkAttachmentReference color_attachment_ref = { 292 .attachment = 0, 293 .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 294 }; 295 296 VkSubpassDescription subpass = { 297 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, 298 .colorAttachmentCount = 1, 299 .pColorAttachments = &color_attachment_ref, 300 }; 301 302 VkSubpassDependency dependency = { 303 .srcSubpass = VK_SUBPASS_EXTERNAL, 304 .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 305 .srcAccessMask = 0, 306 .dstSubpass = 0, 307 .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 308 .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 309 }; 310 311 VkRenderPassCreateInfo render_pass_info = { 312 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 313 .attachmentCount = 1, 314 .pAttachments = &color_attachment, 315 .subpassCount = 1, 316 .pSubpasses = &subpass, 317 .dependencyCount = 1, 318 .pDependencies = &dependency, 319 }; 320 321 if (vkCreateRenderPass(state->vk.device, &render_pass_info, NULL, &state->vk.render_pass) != VK_SUCCESS) 322 return false; 323 324 state->vk.swapchain_framebuffers.ptr = vkdemo_memory_arena_alloc(&memory->permanent, state->vk.swapchain_framebuffers.len * sizeof *state->vk.swapchain_framebuffers.ptr, alignof(VkFramebuffer)); 325 assert(state->vk.swapchain_framebuffers.ptr); 326 327 for (uint32_t i = 0; i < state->vk.swapchain_framebuffers.len; i++) { 328 VkImageView attachments[] = { state->vk.swapchain_image_views.ptr[i], }; 329 330 VkFramebufferCreateInfo framebuffer_info = { 331 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 332 .renderPass = state->vk.render_pass, 333 .attachmentCount = ARRLEN(attachments), 334 .pAttachments = attachments, 335 .width = state->vk.swapchain_extent.width, 336 .height = state->vk.swapchain_extent.height, 337 .layers = 1, 338 }; 339 340 if (vkCreateFramebuffer(state->vk.device, &framebuffer_info, NULL, &state->vk.swapchain_framebuffers.ptr[i]) != VK_SUCCESS) 341 return false; 342 } 343 344 return true; 345 } 346 347 static void 348 destroy_swapchain(struct vkdemo_memory *memory, struct vkdemo_state *state) 349 { 350 (void) memory; 351 352 // TODO: can this cause deadlock? 353 vkDeviceWaitIdle(state->vk.device); 354 355 for (uint32_t i = 0; i < state->vk.swapchain_framebuffers.len; i++) { 356 vkDestroyFramebuffer(state->vk.device, state->vk.swapchain_framebuffers.ptr[i], NULL); 357 } 358 359 vkDestroyRenderPass(state->vk.device, state->vk.render_pass, NULL); 360 361 for (uint32_t i = 0; i < state->vk.swapchain_image_views.len; i++) { 362 vkDestroyImageView(state->vk.device, state->vk.swapchain_image_views.ptr[i], NULL); 363 } 364 365 vkDestroySwapchainKHR(state->vk.device, state->vk.swapchain, NULL); 366 } 367 368 static bool 369 create_shader_module(VkDevice device, uint32_t *code, uint64_t size, VkShaderModule *out) 370 { 371 VkShaderModuleCreateInfo module_info = { 372 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 373 .codeSize = size, 374 .pCode = code, 375 }; 376 377 return vkCreateShaderModule(device, &module_info, NULL, out) == VK_SUCCESS; 378 } 379 380 static bool 381 create_pipeline(struct vkdemo_state *state) 382 { 383 VkShaderModule vert_shader_module; 384 if (!create_shader_module(state->vk.device, vert_shader, sizeof vert_shader, &vert_shader_module)) { 385 fprintf(stderr, "Failed to create vertex shader module!\n"); 386 return false; 387 } 388 389 VkShaderModule frag_shader_module; 390 if (!create_shader_module(state->vk.device, frag_shader, sizeof frag_shader, &frag_shader_module)) { 391 fprintf(stderr, "Failed to create fragment shader module!\n"); 392 return false; 393 } 394 395 VkPipelineShaderStageCreateInfo vert_stage_info = { 396 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 397 .stage = VK_SHADER_STAGE_VERTEX_BIT, 398 .module = vert_shader_module, 399 .pName = "main", 400 }; 401 402 VkPipelineShaderStageCreateInfo frag_stage_info = { 403 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 404 .stage = VK_SHADER_STAGE_FRAGMENT_BIT, 405 .module = frag_shader_module, 406 .pName = "main", 407 }; 408 409 VkPipelineShaderStageCreateInfo shader_stages[] = { 410 vert_stage_info, 411 frag_stage_info, 412 }; 413 414 VkDynamicState dynamic_states[] = { 415 VK_DYNAMIC_STATE_VIEWPORT, 416 VK_DYNAMIC_STATE_SCISSOR, 417 }; 418 419 VkPipelineDynamicStateCreateInfo dynamic_state_info = { 420 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, 421 .dynamicStateCount = ARRLEN(dynamic_states), 422 .pDynamicStates = dynamic_states, 423 }; 424 425 VkPipelineVertexInputStateCreateInfo vertex_input_info = { 426 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 427 .vertexBindingDescriptionCount = 0, 428 .pVertexBindingDescriptions = NULL, 429 .vertexAttributeDescriptionCount = 0, 430 .pVertexAttributeDescriptions = NULL, 431 }; 432 433 VkPipelineInputAssemblyStateCreateInfo input_assembly_info = { 434 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 435 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 436 .primitiveRestartEnable = VK_FALSE, 437 }; 438 439 VkPipelineViewportStateCreateInfo viewport_info = { 440 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 441 .viewportCount = 1, 442 .scissorCount = 1, 443 }; 444 445 VkPipelineRasterizationStateCreateInfo rasteriser_info = { 446 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, 447 .depthClampEnable = VK_FALSE, 448 .rasterizerDiscardEnable = VK_FALSE, 449 .polygonMode = VK_POLYGON_MODE_FILL, 450 .lineWidth = 1.0f, 451 .cullMode = VK_CULL_MODE_BACK_BIT, 452 .frontFace = VK_FRONT_FACE_CLOCKWISE, 453 .depthBiasEnable = VK_FALSE, 454 }; 455 456 VkPipelineMultisampleStateCreateInfo multisample_info = { 457 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 458 .sampleShadingEnable = VK_FALSE, 459 .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, 460 }; 461 462 VkPipelineColorBlendAttachmentState color_blend_attachment = { 463 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, 464 .blendEnable = VK_FALSE, 465 }; 466 467 VkPipelineColorBlendStateCreateInfo color_blend_info = { 468 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 469 .logicOpEnable = VK_FALSE, 470 .attachmentCount = 1, 471 .pAttachments = &color_blend_attachment, 472 }; 473 474 VkPipelineLayoutCreateInfo pipeline_layout_info = { 475 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 476 }; 477 478 if (vkCreatePipelineLayout(state->vk.device, &pipeline_layout_info, NULL, &state->vk.pipeline_layout) != VK_SUCCESS) { 479 fprintf(stderr, "Failed to create pipeline layout!\n"); 480 return false; 481 } 482 483 VkGraphicsPipelineCreateInfo pipeline_info = { 484 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 485 .stageCount = 2, 486 .pStages = shader_stages, 487 .pVertexInputState = &vertex_input_info, 488 .pInputAssemblyState = &input_assembly_info, 489 .pViewportState = &viewport_info, 490 .pRasterizationState = &rasteriser_info, 491 .pMultisampleState = &multisample_info, 492 .pColorBlendState = &color_blend_info, 493 .pDynamicState = &dynamic_state_info, 494 .layout = state->vk.pipeline_layout, 495 .renderPass = state->vk.render_pass, 496 .subpass = 0, 497 .basePipelineHandle = VK_NULL_HANDLE, 498 .basePipelineIndex = -1, 499 }; 500 501 VkPipeline pipeline; 502 if (vkCreateGraphicsPipelines(state->vk.device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &pipeline) != VK_SUCCESS) { 503 fprintf(stderr, "Failed to create pipeline!\n"); 504 return false; 505 } 506 507 state->vk.pipeline = pipeline; 508 509 vkDestroyShaderModule(state->vk.device, frag_shader_module, NULL); 510 vkDestroyShaderModule(state->vk.device, vert_shader_module, NULL); 511 512 return true; 513 } 514 515 static struct vkdemo_state *state; 516 517 bool 518 vkdemo_init(struct vkdemo_memory *memory, VkInstance vk_instance, VkSurfaceKHR vk_surface, uint32_t width, uint32_t height) 519 { 520 state = vkdemo_memory_arena_alloc(&memory->permanent, sizeof *state, alignof(struct vkdemo_state)); 521 assert(state); 522 523 state->vk.instance = vk_instance; 524 state->vk.surface = vk_surface; 525 state->vk.frame_index = 0; 526 527 uint32_t physical_device_count; 528 vkEnumeratePhysicalDevices(vk_instance, &physical_device_count, NULL); 529 530 if (!physical_device_count) { 531 fprintf(stderr, "Failed to find physical devices supporting Vulkan 1.0!\n"); 532 return false; 533 } 534 535 VkPhysicalDevice *physical_devices = _alloca(physical_device_count * sizeof *physical_devices); 536 vkEnumeratePhysicalDevices(vk_instance, &physical_device_count, physical_devices); 537 538 const char *device_extensions[] = { 539 VK_KHR_SWAPCHAIN_EXTENSION_NAME, 540 }; 541 542 state->vk.physical_device = VK_NULL_HANDLE; 543 for (uint32_t i = 0; i < physical_device_count; i++) { 544 if (is_device_suitable(physical_devices[i], vk_surface, device_extensions, ARRLEN(device_extensions))) 545 state->vk.physical_device = physical_devices[i]; 546 } 547 548 if (state->vk.physical_device == VK_NULL_HANDLE) { 549 fprintf(stderr, "Failed to find suitable physical device!\n"); 550 return false; 551 } 552 553 struct queue_family_indices device_queue_families = get_device_queue_families(state->vk.physical_device, vk_surface); 554 555 float queue_priority = 1.0f; 556 557 // TODO: handle case where graphics queue and present queue are separate 558 VkDeviceQueueCreateInfo queue_info = { 559 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 560 .queueFamilyIndex = device_queue_families.graphics_family, 561 .queueCount = 1, 562 .pQueuePriorities = &queue_priority, 563 }; 564 565 VkPhysicalDeviceFeatures device_features = {0}; 566 567 VkDeviceCreateInfo device_info = { 568 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 569 .pQueueCreateInfos = &queue_info, 570 .queueCreateInfoCount = 1, 571 .pEnabledFeatures = &device_features, 572 .enabledExtensionCount = ARRLEN(device_extensions), 573 .ppEnabledExtensionNames = device_extensions, 574 }; 575 576 if (vkCreateDevice(state->vk.physical_device, &device_info, NULL, &state->vk.device) != VK_SUCCESS) { 577 fprintf(stderr, "Failed to create logical device!\n"); 578 return false; 579 } 580 581 vkGetDeviceQueue(state->vk.device, device_queue_families.graphics_family, 0, &state->vk.graphics_queue); 582 vkGetDeviceQueue(state->vk.device, device_queue_families.present_family, 0, &state->vk.present_queue); 583 584 if (!recreate_swapchain(memory, state, width, height, VK_NULL_HANDLE)) { 585 fprintf(stderr, "Failed to create swapchain!\n"); 586 return false; 587 } 588 589 if (!create_pipeline(state)) { 590 fprintf(stderr, "Failed to create graphics pipeline!\n"); 591 return false; 592 } 593 594 VkCommandPoolCreateInfo command_pool_info = { 595 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 596 .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, 597 .queueFamilyIndex = device_queue_families.graphics_family, 598 }; 599 600 if (vkCreateCommandPool(state->vk.device, &command_pool_info, NULL, &state->vk.command_pool) != VK_SUCCESS) { 601 fprintf(stderr, "Failed to create command pool!\n"); 602 return false; 603 } 604 605 VkCommandBufferAllocateInfo command_buffer_alloc_info = { 606 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 607 .commandPool = state->vk.command_pool, 608 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 609 .commandBufferCount = ARRLEN(state->vk.command_buffers), 610 }; 611 612 if (vkAllocateCommandBuffers(state->vk.device, &command_buffer_alloc_info, state->vk.command_buffers) != VK_SUCCESS) { 613 fprintf(stderr, "Failed to allocate command buffers!\n"); 614 return false; 615 } 616 617 VkSemaphoreCreateInfo semaphore_info = { 618 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 619 }; 620 621 VkFenceCreateInfo fence_info = { 622 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 623 .flags = VK_FENCE_CREATE_SIGNALED_BIT, 624 }; 625 626 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { 627 if (vkCreateSemaphore(state->vk.device, &semaphore_info, NULL, &state->vk.sync_objects.image_available[i]) != VK_SUCCESS || 628 vkCreateSemaphore(state->vk.device, &semaphore_info, NULL, &state->vk.sync_objects.render_finished[i]) != VK_SUCCESS || 629 vkCreateFence(state->vk.device, &fence_info, NULL, &state->vk.sync_objects.in_flight[i]) != VK_SUCCESS) { 630 fprintf(stderr, "Failed to create sync objects!\n"); 631 return false; 632 } 633 } 634 635 return true; 636 } 637 638 void 639 vkdemo_update(struct vkdemo_memory *memory) 640 { 641 (void) memory; 642 } 643 644 void 645 vkdemo_render(struct vkdemo_memory *memory, uint32_t width, uint32_t height) 646 { 647 (void) memory; 648 649 uint32_t frame = state->vk.frame_index; 650 state->vk.frame_index = (frame + 1) % MAX_FRAMES_IN_FLIGHT; 651 652 vkWaitForFences(state->vk.device, 1, &state->vk.sync_objects.in_flight[frame], VK_TRUE, UINT64_MAX); 653 654 uint32_t image_index; 655 VkResult result = vkAcquireNextImageKHR(state->vk.device, state->vk.swapchain, UINT64_MAX, state->vk.sync_objects.image_available[frame], VK_NULL_HANDLE, &image_index); 656 657 if (result == VK_ERROR_OUT_OF_DATE_KHR) { 658 destroy_swapchain(memory, state); 659 if (!recreate_swapchain(memory, state, width, height, VK_NULL_HANDLE)) 660 fprintf(stderr, "Failed to recreate swapchain!\n"); 661 return; 662 } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { 663 fprintf(stderr, "Failed to aqcuire swapchain image!\n"); 664 return; 665 } 666 667 vkResetFences(state->vk.device, 1, &state->vk.sync_objects.in_flight[frame]); 668 669 { 670 VkCommandBuffer buffer = state->vk.command_buffers[frame]; 671 vkResetCommandBuffer(buffer, 0); 672 673 VkCommandBufferBeginInfo begin_info = { 674 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 675 }; 676 677 if (vkBeginCommandBuffer(buffer, &begin_info) != VK_SUCCESS) { 678 fprintf(stderr, "Failed to begin recording command buffer!\n"); 679 return; 680 } 681 682 VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; 683 VkRenderPassBeginInfo render_pass_begin_info = { 684 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 685 .renderPass = state->vk.render_pass, 686 .framebuffer = state->vk.swapchain_framebuffers.ptr[image_index], 687 .renderArea.offset = {0, 0}, 688 .renderArea.extent = state->vk.swapchain_extent, 689 .clearValueCount = 1, 690 .pClearValues = &clear_color, 691 }; 692 693 vkCmdBeginRenderPass(buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); 694 695 vkCmdBindPipeline(buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, state->vk.pipeline); 696 697 VkViewport viewport = { 698 .x = 0.0f, 699 .y = 0.0f, 700 .width = (float) state->vk.swapchain_extent.width, 701 .height = (float) state->vk.swapchain_extent.height, 702 .minDepth = 0.0f, 703 .maxDepth = 1.0f, 704 }; 705 706 vkCmdSetViewport(buffer, 0, 1, &viewport); 707 708 VkRect2D scissor = { 709 .offset = {0, 0}, 710 .extent = state->vk.swapchain_extent, 711 }; 712 713 vkCmdSetScissor(buffer, 0, 1, &scissor); 714 715 uint32_t vertex_count = 3, instance_count = 1, first_vertex = 0, first_instance = 0; 716 vkCmdDraw(buffer, vertex_count, instance_count, first_vertex, first_instance); 717 718 vkCmdEndRenderPass(buffer); 719 720 if (vkEndCommandBuffer(buffer) != VK_SUCCESS) { 721 fprintf(stderr, "Failed to end recording command buffer!\n"); 722 return; 723 } 724 } 725 726 VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; 727 728 VkSubmitInfo submit_info = { 729 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 730 .waitSemaphoreCount = 1, 731 .pWaitSemaphores = &state->vk.sync_objects.image_available[frame], 732 .pWaitDstStageMask = wait_stages, 733 .signalSemaphoreCount = 1, 734 .pSignalSemaphores = &state->vk.sync_objects.render_finished[frame], 735 .commandBufferCount = 1, 736 .pCommandBuffers = &state->vk.command_buffers[frame], 737 }; 738 739 if (vkQueueSubmit(state->vk.graphics_queue, 1, &submit_info, state->vk.sync_objects.in_flight[frame]) != VK_SUCCESS) { 740 fprintf(stderr, "Failed to submit command buffer!\n"); 741 return; 742 } 743 744 VkPresentInfoKHR present_info = { 745 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 746 .waitSemaphoreCount = 1, 747 .pWaitSemaphores = &state->vk.sync_objects.render_finished[frame], 748 .swapchainCount = 1, 749 .pSwapchains = &state->vk.swapchain, 750 .pImageIndices = &image_index, 751 }; 752 753 vkQueuePresentKHR(state->vk.present_queue, &present_info); 754 } 755 756 void 757 vkdemo_free(struct vkdemo_memory *memory) 758 { 759 vkDeviceWaitIdle(state->vk.device); 760 761 destroy_swapchain(memory, state); 762 763 vkDestroyPipeline(state->vk.device, state->vk.pipeline, NULL); 764 vkDestroyPipelineLayout(state->vk.device, state->vk.pipeline_layout, NULL); 765 766 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { 767 vkDestroySemaphore(state->vk.device, state->vk.sync_objects.render_finished[i], NULL); 768 vkDestroySemaphore(state->vk.device, state->vk.sync_objects.image_available[i], NULL); 769 vkDestroyFence(state->vk.device, state->vk.sync_objects.in_flight[i], NULL); 770 } 771 772 vkDestroyCommandPool(state->vk.device, state->vk.command_pool, NULL); 773 774 vkDestroyDevice(state->vk.device, NULL); 775 }