starfield

starfield.git
git clone git://git.lenczewski.org/starfield.git
Log | Files | Refs | Submodules | README | LICENSE

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 }