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