Created
July 3, 2020 23:47
-
-
Save colbyhall/a2c4176b4ae080d75b9142cef1680dfb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "vulkan.h" | |
| #include "string.h" | |
| // #include <glslang/Public/ShaderLang.h> | |
| // #include <glslang/Include/glslang_c_interface.h> | |
| Render_Context* g_render_context = nullptr; | |
| static const char* const instance_layers[] = { | |
| "VK_LAYER_KHRONOS_validation", | |
| // VK_EXT_DEBUG_UTILS_EXTENSION_NAME, | |
| }; | |
| static VKAPI_ATTR VkBool32 VKAPI_CALL | |
| vulkan_debug_callback( | |
| VkDebugUtilsMessageSeverityFlagBitsEXT severity, | |
| VkDebugUtilsMessageTypeFlagsEXT type, | |
| const VkDebugUtilsMessengerCallbackDataEXT* callback_data, | |
| void* user_data | |
| ) { | |
| if (severity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { | |
| log_error("[Vulkan] %s", callback_data->pMessage); | |
| } | |
| return true; | |
| } | |
| VkInstanceCreateInfo make_instance_create_info(); | |
| void create_surface(Platform* platform); | |
| void init_vulkan(Platform* platform) { | |
| g_render_context = alloc_struct(platform->permanent_arena, Render_Context); | |
| defer(g_render_context->initialized = true); | |
| // @NOTE(colby): Create the vulkan instance | |
| { | |
| VkInstanceCreateInfo create_info = make_instance_create_info(); // Abstracted into a function because os specific implementation | |
| create_info.ppEnabledLayerNames = instance_layers; | |
| create_info.enabledLayerCount = ARRAY_COUNT(instance_layers); | |
| VkResult result = vkCreateInstance(&create_info, nullptr, &g_render_context->instance); | |
| assert(result == VK_SUCCESS); | |
| } | |
| // @NOTE(colby): Create the debug messenger | |
| /** | |
| * Apparently this extension isn't on this machine | |
| { | |
| const VkDebugUtilsMessengerCreateInfoEXT create_info = { | |
| VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, | |
| nullptr, | |
| 0, | |
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | | |
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | | |
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, | |
| VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | | |
| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | | |
| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, | |
| vulkan_debug_callback, | |
| nullptr | |
| }; | |
| PFN_vkCreateDebugUtilsMessengerEXT const vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(g_render_context->instance, "vkCreateDebugUtilsMessengerEXT"); | |
| VkResult result = vkCreateDebugUtilsMessengerEXT(g_render_context->instance, &create_info, nullptr, &g_render_context->debug_messenger); | |
| assert(result == VK_SUCCESS); | |
| } | |
| */ | |
| create_surface(platform); // Abstracted into a function because os specific implementation | |
| // @NOTE(colby): We now need to pick our actual GPU | |
| { | |
| u32 device_count = 0; | |
| vkEnumeratePhysicalDevices(g_render_context->instance, &device_count, nullptr); | |
| assert(device_count > 0); | |
| Array<VkPhysicalDevice> devices = make_array<VkPhysicalDevice>(device_count); | |
| defer(array_free(&devices)); | |
| devices.len = device_count; | |
| vkEnumeratePhysicalDevices(g_render_context->instance, &device_count, devices.data); | |
| VkPhysicalDevice selected_gpu = VK_NULL_HANDLE; | |
| for (VkPhysicalDevice device : devices) { | |
| VkPhysicalDeviceProperties properties; | |
| vkGetPhysicalDeviceProperties(device, &properties); | |
| VkPhysicalDeviceFeatures features; | |
| vkGetPhysicalDeviceFeatures(device, &features); | |
| // @TODO(colby): Maybe do more checking with features we actually will need like KHR Swapchain support? | |
| if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && features.geometryShader) { | |
| selected_gpu = device; | |
| break; | |
| } | |
| } | |
| assert(selected_gpu != VK_NULL_HANDLE); | |
| g_render_context->physical_gpu = selected_gpu; | |
| } | |
| u32 queue_family_count = 0; | |
| vkGetPhysicalDeviceQueueFamilyProperties(g_render_context->physical_gpu, &queue_family_count, nullptr); | |
| assert(queue_family_count > 0); | |
| Array<VkQueueFamilyProperties> queue_families = make_array<VkQueueFamilyProperties>(queue_family_count); | |
| defer(array_free(&queue_families)); | |
| queue_families.len = queue_family_count; | |
| vkGetPhysicalDeviceQueueFamilyProperties(g_render_context->physical_gpu, &queue_family_count, queue_families.data); | |
| int graphics_family_index = -1; | |
| int surface_family_index = -1; | |
| for (usize i = 0; i < queue_families.len; ++i) { | |
| const VkQueueFamilyProperties& queue_family = queue_families[i]; | |
| if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { | |
| graphics_family_index = (int)i; | |
| } | |
| VkBool32 present_support = false; | |
| vkGetPhysicalDeviceSurfaceSupportKHR(g_render_context->physical_gpu, (u32)i, g_render_context->surface, &present_support); | |
| if (present_support) { | |
| surface_family_index = (int)i; | |
| } | |
| } | |
| assert(graphics_family_index != -1 && surface_family_index != -1); | |
| const u32 queue_family_indices[] = { | |
| (u32)graphics_family_index, | |
| (u32)surface_family_index | |
| }; | |
| // @NOTE(colby): Setup logical device and queues | |
| { | |
| Array<VkDeviceQueueCreateInfo> queues_create_info = make_array<VkDeviceQueueCreateInfo>(ARRAY_COUNT(queue_family_indices)); | |
| defer(array_free(&queues_create_info)); | |
| f32 queue_priority = 1.f; | |
| for (int i = 0; i < ARRAY_COUNT(queue_family_indices); ++i) { | |
| VkDeviceQueueCreateInfo create_info = { | |
| VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| (u32)queue_family_indices[i], | |
| 1, | |
| &queue_priority | |
| }; | |
| array_push(&queues_create_info, create_info); | |
| } | |
| VkPhysicalDeviceFeatures logical_device_features = {}; | |
| static const char* const logical_device_extensions[] = { | |
| VK_KHR_SWAPCHAIN_EXTENSION_NAME, | |
| }; | |
| VkDeviceCreateInfo logical_device_create_info = { | |
| VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| (u32)queues_create_info.len, | |
| queues_create_info.data, | |
| ARRAY_COUNT(instance_layers), | |
| instance_layers, | |
| ARRAY_COUNT(logical_device_extensions), | |
| logical_device_extensions, | |
| &logical_device_features | |
| }; | |
| VkResult result = vkCreateDevice( | |
| g_render_context->physical_gpu, | |
| &logical_device_create_info, | |
| nullptr, | |
| &g_render_context->logical_gpu | |
| ); | |
| assert(result == VK_SUCCESS); | |
| vkGetDeviceQueue( | |
| g_render_context->logical_gpu, | |
| graphics_family_index, | |
| 0, | |
| &g_render_context->graphics_queue | |
| ); | |
| vkGetDeviceQueue( | |
| g_render_context->logical_gpu, | |
| surface_family_index, | |
| 0, | |
| &g_render_context->presentation_queue | |
| ); | |
| } | |
| // @NOTE(colby): Swap chain shit. | |
| // @TODO(colby): Abstract this out since it will need to be recreated with every window change | |
| { | |
| VkSurfaceCapabilitiesKHR surface_capabilities; | |
| vkGetPhysicalDeviceSurfaceCapabilitiesKHR( | |
| g_render_context->physical_gpu, | |
| g_render_context->surface, | |
| &surface_capabilities | |
| ); | |
| u32 format_count; | |
| vkGetPhysicalDeviceSurfaceFormatsKHR( | |
| g_render_context->physical_gpu, | |
| g_render_context->surface, | |
| &format_count, | |
| nullptr | |
| ); | |
| Array<VkSurfaceFormatKHR> formats = make_array<VkSurfaceFormatKHR>(format_count); | |
| defer(array_free(&formats)); | |
| formats.len = format_count; | |
| vkGetPhysicalDeviceSurfaceFormatsKHR( | |
| g_render_context->physical_gpu, | |
| g_render_context->surface, | |
| &format_count, | |
| formats.data | |
| ); | |
| VkSurfaceFormatKHR selected_format = {}; | |
| b32 found_format = false; | |
| for (VkSurfaceFormatKHR format : formats) { | |
| if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { | |
| found_format = true; | |
| selected_format = format; | |
| break; | |
| } | |
| } | |
| assert(found_format); | |
| VkPresentModeKHR present_modes[12]; | |
| u32 present_mode_count; | |
| vkGetPhysicalDeviceSurfacePresentModesKHR( | |
| g_render_context->physical_gpu, | |
| g_render_context->surface, | |
| &present_mode_count, | |
| present_modes | |
| ); | |
| VkPresentModeKHR selected_present_mode = VK_PRESENT_MODE_FIFO_KHR; | |
| VkSwapchainCreateInfoKHR create_info = { | |
| VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, | |
| nullptr, | |
| 0, | |
| g_render_context->surface, | |
| surface_capabilities.minImageCount, | |
| selected_format.format, | |
| selected_format.colorSpace, | |
| surface_capabilities.currentExtent, | |
| 1, | |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, | |
| VK_SHARING_MODE_CONCURRENT, | |
| ARRAY_COUNT(queue_family_indices), | |
| queue_family_indices, | |
| surface_capabilities.currentTransform, | |
| VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, | |
| selected_present_mode, | |
| VK_TRUE, | |
| VK_NULL_HANDLE, | |
| }; | |
| VkResult result = vkCreateSwapchainKHR( | |
| g_render_context->logical_gpu, | |
| &create_info, | |
| nullptr, | |
| &g_render_context->swap_chain | |
| ); | |
| assert(result == VK_SUCCESS); | |
| g_render_context->swap_chain_extents = surface_capabilities.currentExtent; | |
| u32 image_count = 0; | |
| vkGetSwapchainImagesKHR( | |
| g_render_context->logical_gpu, | |
| g_render_context->swap_chain, | |
| &image_count, | |
| nullptr | |
| ); | |
| array_reserve(&g_render_context->swap_chain_images, image_count); | |
| g_render_context->swap_chain_images.len = image_count; | |
| vkGetSwapchainImagesKHR( | |
| g_render_context->logical_gpu, | |
| g_render_context->swap_chain, | |
| &image_count, | |
| g_render_context->swap_chain_images.data | |
| ); | |
| array_reserve(&g_render_context->swap_chain_image_views, image_count); | |
| g_render_context->swap_chain_image_views.len = image_count; | |
| for (usize i = 0; i < g_render_context->swap_chain_images.len; ++i) { | |
| static const VkComponentMapping component_mapping = { | |
| VK_COMPONENT_SWIZZLE_IDENTITY, | |
| VK_COMPONENT_SWIZZLE_IDENTITY, | |
| VK_COMPONENT_SWIZZLE_IDENTITY, | |
| VK_COMPONENT_SWIZZLE_IDENTITY, | |
| }; | |
| static const VkImageSubresourceRange subresource_range = { | |
| VK_IMAGE_ASPECT_COLOR_BIT, | |
| 0, | |
| 1, | |
| 0, | |
| 1 | |
| }; | |
| VkImageViewCreateInfo image_create_info = { | |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| g_render_context->swap_chain_images[i], | |
| VK_IMAGE_VIEW_TYPE_2D, | |
| VK_FORMAT_B8G8R8A8_SRGB, | |
| component_mapping, | |
| subresource_range | |
| }; | |
| result = vkCreateImageView( | |
| g_render_context->logical_gpu, | |
| &image_create_info, | |
| nullptr, | |
| &g_render_context->swap_chain_image_views[i] | |
| ); | |
| assert(result == VK_SUCCESS); | |
| } | |
| } | |
| // @NOTE(colby): Create render pass | |
| { | |
| VkAttachmentDescription color_attachment = { | |
| 0, | |
| VK_FORMAT_B8G8R8A8_SRGB, | |
| VK_SAMPLE_COUNT_1_BIT, | |
| VK_ATTACHMENT_LOAD_OP_CLEAR, | |
| VK_ATTACHMENT_STORE_OP_STORE, | |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, | |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, | |
| VK_IMAGE_LAYOUT_UNDEFINED, | |
| VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, | |
| }; | |
| VkAttachmentReference color_attachment_ref = { | |
| 0, | |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, | |
| }; | |
| VkSubpassDescription subpass = {}; | |
| subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; | |
| subpass.colorAttachmentCount = 1; | |
| subpass.pColorAttachments = &color_attachment_ref; | |
| VkSubpassDependency dependency = { | |
| VK_SUBPASS_EXTERNAL, | |
| 0, | |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | |
| 0, | |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, | |
| 0 | |
| }; | |
| VkRenderPassCreateInfo create_info = { | |
| VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| 1, | |
| &color_attachment, | |
| 1, | |
| &subpass, | |
| 1, | |
| &dependency, | |
| }; | |
| VkResult result = vkCreateRenderPass( | |
| g_render_context->logical_gpu, | |
| &create_info, | |
| nullptr, | |
| &g_render_context->render_pass | |
| ); | |
| assert(result == VK_SUCCESS); | |
| } | |
| // @NOTE(colby): Pipeline creation | |
| { | |
| VkShaderModule frag_shader_module; | |
| VkShaderModule vert_shader_module; | |
| // @NOTE(colby): Shader creation | |
| { | |
| String vert; | |
| if (!os_read_file_into_string("assets\\shaders\\triangle.vspv", &vert)) { | |
| assert(false); | |
| } | |
| VkShaderModuleCreateInfo shader_create_info { | |
| VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| vert.len, | |
| (const u32*)vert.data | |
| }; | |
| VkResult result = vkCreateShaderModule( | |
| g_render_context->logical_gpu, | |
| &shader_create_info, | |
| nullptr, | |
| &vert_shader_module | |
| ); | |
| assert(result == VK_SUCCESS); | |
| String frag; | |
| if (!os_read_file_into_string("assets\\shaders\\triangle.fspv", &frag)) { | |
| assert(false); | |
| } | |
| shader_create_info.codeSize = frag.len; | |
| shader_create_info.pCode = (const u32*)frag.data; | |
| result = vkCreateShaderModule( | |
| g_render_context->logical_gpu, | |
| &shader_create_info, | |
| nullptr, | |
| &frag_shader_module | |
| ); | |
| assert(result == VK_SUCCESS); | |
| } | |
| VkPipelineShaderStageCreateInfo vert_shader_stage_info = { | |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| VK_SHADER_STAGE_VERTEX_BIT, | |
| vert_shader_module, | |
| "main", | |
| nullptr | |
| }; | |
| VkPipelineShaderStageCreateInfo frag_shader_stage_info = { | |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| VK_SHADER_STAGE_FRAGMENT_BIT, | |
| frag_shader_module, | |
| "main", | |
| nullptr | |
| }; | |
| VkPipelineShaderStageCreateInfo shader_stages[] = { | |
| vert_shader_stage_info, | |
| frag_shader_stage_info, | |
| }; | |
| // @NOTE(colby): Define vertex attributes | |
| VkPipelineVertexInputStateCreateInfo vertex_input_state = { | |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| 0, | |
| nullptr, | |
| 0, | |
| nullptr, | |
| }; | |
| VkPipelineInputAssemblyStateCreateInfo input_assembly_state = { | |
| VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, | |
| VK_FALSE, | |
| }; | |
| VkViewport viewport = { | |
| 0.f, | |
| 0.f, | |
| (f32)platform->window_width, | |
| (f32)platform->window_height, | |
| 0.f, | |
| 1.f, | |
| }; | |
| VkRect2D scissor = { | |
| { 0, 0 }, | |
| g_render_context->swap_chain_extents, | |
| }; | |
| VkPipelineViewportStateCreateInfo viewport_state = { | |
| VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| 1, | |
| &viewport, | |
| 1, | |
| &scissor, | |
| }; | |
| VkPipelineRasterizationStateCreateInfo rasterizer_state = { | |
| VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| VK_FALSE, | |
| VK_FALSE, | |
| VK_POLYGON_MODE_FILL, | |
| VK_CULL_MODE_BACK_BIT, | |
| VK_FRONT_FACE_CLOCKWISE, | |
| VK_FALSE, | |
| 0.f, | |
| 0.f, | |
| 0.f, | |
| 1.f, // line width | |
| }; | |
| VkPipelineMultisampleStateCreateInfo multisample_state = { | |
| VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| VK_SAMPLE_COUNT_1_BIT, | |
| VK_FALSE, | |
| 1.f, | |
| nullptr, | |
| VK_FALSE, | |
| VK_FALSE, | |
| }; | |
| VkPipelineColorBlendAttachmentState color_blend_attachment = { | |
| VK_FALSE, | |
| VK_BLEND_FACTOR_ONE, | |
| VK_BLEND_FACTOR_ZERO, | |
| VK_BLEND_OP_ADD, | |
| VK_BLEND_FACTOR_ONE, | |
| VK_BLEND_FACTOR_ZERO, | |
| VK_BLEND_OP_ADD, | |
| VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | |
| }; | |
| VkPipelineColorBlendStateCreateInfo color_blend_state = { | |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| VK_FALSE, | |
| VK_LOGIC_OP_COPY, | |
| 1, | |
| &color_blend_attachment, | |
| { }, | |
| }; | |
| VkDynamicState dynamic_states[] = { | |
| VK_DYNAMIC_STATE_VIEWPORT, | |
| }; | |
| VkPipelineDynamicStateCreateInfo dynamic_state = { | |
| VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| ARRAY_COUNT(dynamic_states), | |
| dynamic_states, | |
| }; | |
| VkPipelineLayoutCreateInfo pipeline_layout_info = { | |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| 0, | |
| nullptr, | |
| 0, | |
| nullptr, | |
| }; | |
| VkResult result = vkCreatePipelineLayout( | |
| g_render_context->logical_gpu, | |
| &pipeline_layout_info, | |
| nullptr, | |
| &g_render_context->pipeline_layout | |
| ); | |
| assert(result == VK_SUCCESS); | |
| VkGraphicsPipelineCreateInfo pipeline_create_info = { | |
| VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| ARRAY_COUNT(shader_stages), | |
| shader_stages, | |
| &vertex_input_state, | |
| &input_assembly_state, | |
| nullptr, | |
| &viewport_state, | |
| &rasterizer_state, | |
| &multisample_state, | |
| nullptr, // @TODO(colby): depth stencil state | |
| &color_blend_state, | |
| nullptr, // @TODO(colby): dynamic state | |
| g_render_context->pipeline_layout, | |
| g_render_context->render_pass, | |
| 0, | |
| VK_NULL_HANDLE, | |
| -1, | |
| }; | |
| result = vkCreateGraphicsPipelines( | |
| g_render_context->logical_gpu, | |
| VK_NULL_HANDLE, // @Incomplete(colby): Look into pipeline caches | |
| 1, | |
| &pipeline_create_info, | |
| nullptr, | |
| &g_render_context->graphics_pipeline | |
| ); | |
| assert(result == VK_SUCCESS); | |
| } | |
| // @NOTE(colby): Create swap chain framebuffers | |
| { | |
| g_render_context->swap_chain_framebuffers = make_array<VkFramebuffer>(g_render_context->swap_chain_image_views.len); | |
| g_render_context->swap_chain_framebuffers.len = g_render_context->swap_chain_framebuffers.cap; | |
| for (usize i = 0; i < g_render_context->swap_chain_image_views.len; ++i) { | |
| VkImageView attachments[] = { | |
| g_render_context->swap_chain_image_views[i], | |
| }; | |
| VkFramebufferCreateInfo create_info = { | |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| g_render_context->render_pass, | |
| ARRAY_COUNT(attachments), | |
| attachments, | |
| platform->window_width, | |
| platform->window_height, | |
| 1, | |
| }; | |
| VkResult result = vkCreateFramebuffer( | |
| g_render_context->logical_gpu, | |
| &create_info, | |
| nullptr, | |
| &g_render_context->swap_chain_framebuffers[i] | |
| ); | |
| assert(result == VK_SUCCESS); | |
| } | |
| } | |
| // @NOTE(colby): create command buffers and do triangle draw | |
| { | |
| // @NOTE(colby): Create a command pool which is used to allocate command buffers | |
| VkCommandPoolCreateInfo pool_create_info = { | |
| VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| (u32)graphics_family_index, | |
| }; | |
| VkResult result = vkCreateCommandPool( | |
| g_render_context->logical_gpu, | |
| &pool_create_info, | |
| nullptr, | |
| &g_render_context->command_pool | |
| ); | |
| assert(result == VK_SUCCESS); | |
| // @@NOTE(colby): Allocate command buffer | |
| g_render_context->command_buffers = make_array<VkCommandBuffer>(g_render_context->swap_chain_images.len); | |
| g_render_context->command_buffers.len = g_render_context->command_buffers.cap; | |
| VkCommandBufferAllocateInfo alloc_info = { | |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, | |
| nullptr, | |
| g_render_context->command_pool, | |
| VK_COMMAND_BUFFER_LEVEL_PRIMARY, | |
| (u32)g_render_context->command_buffers.len, | |
| }; | |
| result = vkAllocateCommandBuffers( | |
| g_render_context->logical_gpu, | |
| &alloc_info, | |
| g_render_context->command_buffers.data | |
| ); | |
| assert(result == VK_SUCCESS); | |
| // @NOTE(colby): record draw commands to command buffers | |
| for (usize i = 0; i < g_render_context->command_buffers.len; ++i) { | |
| VkCommandBuffer command_buffer = g_render_context->command_buffers[i]; | |
| VkCommandBufferBeginInfo begin_info = { | |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | |
| nullptr, | |
| 0, | |
| nullptr, | |
| }; | |
| result = vkBeginCommandBuffer(command_buffer, &begin_info); | |
| assert(result == VK_SUCCESS); | |
| VkClearValue clear_color = { 0.f, 0.f, 0.f, 1.f }; | |
| // @NOTE(colby): Start render pass | |
| VkRenderPassBeginInfo render_pass_begin_info = { | |
| VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | |
| nullptr, | |
| g_render_context->render_pass, | |
| g_render_context->swap_chain_framebuffers[i], | |
| { | |
| { 0, 0 }, | |
| g_render_context->swap_chain_extents, | |
| }, | |
| 1, | |
| &clear_color, | |
| }; | |
| vkCmdBeginRenderPass( | |
| command_buffer, | |
| &render_pass_begin_info, | |
| VK_SUBPASS_CONTENTS_INLINE | |
| ); | |
| vkCmdBindPipeline( | |
| command_buffer, | |
| VK_PIPELINE_BIND_POINT_GRAPHICS, | |
| g_render_context->graphics_pipeline | |
| ); | |
| vkCmdDraw(command_buffer, 3, 1, 0, 0); | |
| vkCmdEndRenderPass(command_buffer); | |
| result = vkEndCommandBuffer(command_buffer); | |
| assert(result == VK_SUCCESS); | |
| } | |
| } | |
| // @NOTE(colby): Create semaphores | |
| { | |
| VkSemaphoreCreateInfo create_info = { | |
| VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| }; | |
| VkResult result = vkCreateSemaphore( | |
| g_render_context->logical_gpu, | |
| &create_info, | |
| nullptr, | |
| &g_render_context->image_available_semaphore | |
| ); | |
| assert(result == VK_SUCCESS); | |
| result = vkCreateSemaphore( | |
| g_render_context->logical_gpu, | |
| &create_info, | |
| nullptr, | |
| &g_render_context->render_finished_semaphore | |
| ); | |
| assert(result == VK_SUCCESS); | |
| } | |
| // glslang_initialize_process(); | |
| } | |
| void draw_triangle() { | |
| // @NOTE(colby): Wait untl we have an image we can draw to | |
| u32 image_index; | |
| vkAcquireNextImageKHR( | |
| g_render_context->logical_gpu, | |
| g_render_context->swap_chain, | |
| U64_MAX, | |
| g_render_context->image_available_semaphore, | |
| VK_NULL_HANDLE, | |
| &image_index | |
| ); | |
| VkSemaphore wait_semaphores[] = { | |
| g_render_context->image_available_semaphore, | |
| }; | |
| VkPipelineStageFlags wait_stages[] = { | |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | |
| }; | |
| VkSemaphore signal_semaphores[] = { | |
| g_render_context->render_finished_semaphore, | |
| }; | |
| VkSubmitInfo submit_info = { | |
| VK_STRUCTURE_TYPE_SUBMIT_INFO, | |
| nullptr, | |
| ARRAY_COUNT(wait_semaphores), | |
| wait_semaphores, | |
| wait_stages, | |
| 1, | |
| &g_render_context->command_buffers[image_index], | |
| ARRAY_COUNT(signal_semaphores), | |
| signal_semaphores, | |
| }; | |
| VkResult result = vkQueueSubmit( | |
| g_render_context->graphics_queue, | |
| 1, | |
| &submit_info, | |
| VK_NULL_HANDLE | |
| ); | |
| assert(result == VK_SUCCESS); | |
| VkPresentInfoKHR present_info = { | |
| VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, | |
| nullptr, | |
| 1, | |
| signal_semaphores, | |
| 1, | |
| &g_render_context->swap_chain, | |
| &image_index, | |
| nullptr, | |
| }; | |
| vkQueuePresentKHR(g_render_context->presentation_queue, &present_info); | |
| } | |
| #if 0 | |
| static const | |
| glslang_resource_s default_glslang_resources = { | |
| /* .MaxLights = */ 32, | |
| /* .MaxClipPlanes = */ 6, | |
| /* .MaxTextureUnits = */ 32, | |
| /* .MaxTextureCoords = */ 32, | |
| /* .MaxVertexAttribs = */ 64, | |
| /* .MaxVertexUniformComponents = */ 4096, | |
| /* .MaxVaryingFloats = */ 64, | |
| /* .MaxVertexTextureImageUnits = */ 32, | |
| /* .MaxCombinedTextureImageUnits = */ 80, | |
| /* .MaxTextureImageUnits = */ 32, | |
| /* .MaxFragmentUniformComponents = */ 4096, | |
| /* .MaxDrawBuffers = */ 32, | |
| /* .MaxVertexUniformVectors = */ 128, | |
| /* .MaxVaryingVectors = */ 8, | |
| /* .MaxFragmentUniformVectors = */ 16, | |
| /* .MaxVertexOutputVectors = */ 16, | |
| /* .MaxFragmentInputVectors = */ 15, | |
| /* .MinProgramTexelOffset = */ -8, | |
| /* .MaxProgramTexelOffset = */ 7, | |
| /* .MaxClipDistances = */ 8, | |
| /* .MaxComputeWorkGroupCountX = */ 65535, | |
| /* .MaxComputeWorkGroupCountY = */ 65535, | |
| /* .MaxComputeWorkGroupCountZ = */ 65535, | |
| /* .MaxComputeWorkGroupSizeX = */ 1024, | |
| /* .MaxComputeWorkGroupSizeY = */ 1024, | |
| /* .MaxComputeWorkGroupSizeZ = */ 64, | |
| /* .MaxComputeUniformComponents = */ 1024, | |
| /* .MaxComputeTextureImageUnits = */ 16, | |
| /* .MaxComputeImageUniforms = */ 8, | |
| /* .MaxComputeAtomicCounters = */ 8, | |
| /* .MaxComputeAtomicCounterBuffers = */ 1, | |
| /* .MaxVaryingComponents = */ 60, | |
| /* .MaxVertexOutputComponents = */ 64, | |
| /* .MaxGeometryInputComponents = */ 64, | |
| /* .MaxGeometryOutputComponents = */ 128, | |
| /* .MaxFragmentInputComponents = */ 128, | |
| /* .MaxImageUnits = */ 8, | |
| /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8, | |
| /* .MaxCombinedShaderOutputResources = */ 8, | |
| /* .MaxImageSamples = */ 0, | |
| /* .MaxVertexImageUniforms = */ 0, | |
| /* .MaxTessControlImageUniforms = */ 0, | |
| /* .MaxTessEvaluationImageUniforms = */ 0, | |
| /* .MaxGeometryImageUniforms = */ 0, | |
| /* .MaxFragmentImageUniforms = */ 8, | |
| /* .MaxCombinedImageUniforms = */ 8, | |
| /* .MaxGeometryTextureImageUnits = */ 16, | |
| /* .MaxGeometryOutputVertices = */ 256, | |
| /* .MaxGeometryTotalOutputComponents = */ 1024, | |
| /* .MaxGeometryUniformComponents = */ 1024, | |
| /* .MaxGeometryVaryingComponents = */ 64, | |
| /* .MaxTessControlInputComponents = */ 128, | |
| /* .MaxTessControlOutputComponents = */ 128, | |
| /* .MaxTessControlTextureImageUnits = */ 16, | |
| /* .MaxTessControlUniformComponents = */ 1024, | |
| /* .MaxTessControlTotalOutputComponents = */ 4096, | |
| /* .MaxTessEvaluationInputComponents = */ 128, | |
| /* .MaxTessEvaluationOutputComponents = */ 128, | |
| /* .MaxTessEvaluationTextureImageUnits = */ 16, | |
| /* .MaxTessEvaluationUniformComponents = */ 1024, | |
| /* .MaxTessPatchComponents = */ 120, | |
| /* .MaxPatchVertices = */ 32, | |
| /* .MaxTessGenLevel = */ 64, | |
| /* .MaxViewports = */ 16, | |
| /* .MaxVertexAtomicCounters = */ 0, | |
| /* .MaxTessControlAtomicCounters = */ 0, | |
| /* .MaxTessEvaluationAtomicCounters = */ 0, | |
| /* .MaxGeometryAtomicCounters = */ 0, | |
| /* .MaxFragmentAtomicCounters = */ 8, | |
| /* .MaxCombinedAtomicCounters = */ 8, | |
| /* .MaxAtomicCounterBindings = */ 1, | |
| /* .MaxVertexAtomicCounterBuffers = */ 0, | |
| /* .MaxTessControlAtomicCounterBuffers = */ 0, | |
| /* .MaxTessEvaluationAtomicCounterBuffers = */ 0, | |
| /* .MaxGeometryAtomicCounterBuffers = */ 0, | |
| /* .MaxFragmentAtomicCounterBuffers = */ 1, | |
| /* .MaxCombinedAtomicCounterBuffers = */ 1, | |
| /* .MaxAtomicCounterBufferSize = */ 16384, | |
| /* .MaxTransformFeedbackBuffers = */ 4, | |
| /* .MaxTransformFeedbackInterleavedComponents = */ 64, | |
| /* .MaxCullDistances = */ 8, | |
| /* .MaxCombinedClipAndCullDistances = */ 8, | |
| /* .MaxSamples = */ 4, | |
| /* .maxMeshOutputVerticesNV = */ 256, | |
| /* .maxMeshOutputPrimitivesNV = */ 512, | |
| /* .maxMeshWorkGroupSizeX_NV = */ 32, | |
| /* .maxMeshWorkGroupSizeY_NV = */ 1, | |
| /* .maxMeshWorkGroupSizeZ_NV = */ 1, | |
| /* .maxTaskWorkGroupSizeX_NV = */ 32, | |
| /* .maxTaskWorkGroupSizeY_NV = */ 1, | |
| /* .maxTaskWorkGroupSizeZ_NV = */ 1, | |
| /* .maxMeshViewCountNV = */ 4, | |
| /* .maxDualSourceDrawBuffersEXT = */ 1, | |
| /* .limits = */ { | |
| /* .nonInductiveForLoops = */ 1, | |
| /* .whileLoops = */ 1, | |
| /* .doWhileLoops = */ 1, | |
| /* .generalUniformIndexing = */ 1, | |
| /* .generalAttributeMatrixVectorIndexing = */ 1, | |
| /* .generalVaryingIndexing = */ 1, | |
| /* .generalSamplerIndexing = */ 1, | |
| /* .generalVariableIndexing = */ 1, | |
| /* .generalConstantMatrixVectorIndexing = */ 1, | |
| } | |
| }; | |
| b32 make_shader(Shader_Type type, String contents, Shader* out_shader) { | |
| glslang_stage_t stage = {}; | |
| switch (type) { | |
| case ST_Fragment: | |
| stage = GLSLANG_STAGE_FRAGMENT; | |
| break; | |
| case ST_Vertex: | |
| stage = GLSLANG_STAGE_VERTEX; | |
| break; | |
| default: invalid_code_path; | |
| }; | |
| const glslang_input_t input = { | |
| GLSLANG_SOURCE_GLSL, | |
| stage, | |
| GLSLANG_CLIENT_VULKAN, | |
| GLSLANG_TARGET_VULKAN_1_1, | |
| GLSLANG_TARGET_SPV, | |
| GLSLANG_TARGET_SPV_1_3, | |
| (const char*)contents.data, | |
| 100, | |
| GLSLANG_NO_PROFILE, | |
| false, | |
| false, | |
| GLSLANG_MSG_DEFAULT_BIT, | |
| &default_glslang_resources, | |
| }; | |
| glslang_shader_t* shader = glslang_shader_create(&input); | |
| defer(glslang_shader_delete(shader)); | |
| if (!glslang_shader_preprocess(shader, &input)) { | |
| // @TODO(colby): do error handling | |
| return false; | |
| } | |
| if (!glslang_shader_parse(shader, &input)) { | |
| // @TODO(colby): do error handling | |
| return false; | |
| } | |
| glslang_program_t* program = glslang_program_create(); | |
| defer(glslang_program_delete(program)); | |
| glslang_program_add_shader(program, shader); | |
| if (!glslang_program_link(program, GLSLANG_MSG_SPV_RULES_BIT | GLSLANG_MSG_VULKAN_RULES_BIT)) { | |
| // @TODO(colby): do error handling | |
| return false; | |
| } | |
| glslang_program_SPIRV_generate(program, stage); | |
| if (const char* message = glslang_program_SPIRV_get_messages(program)) { | |
| // @TODO(colby): do error handling | |
| } | |
| const VkShaderModuleCreateInfo create_info = { | |
| VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | |
| nullptr, | |
| 0, | |
| glslang_program_SPIRV_get_size(program) * sizeof(u32), | |
| glslang_program_SPIRV_get_ptr(program), | |
| }; | |
| VkShaderModule module; | |
| const VkResult result = vkCreateShaderModule(g_render_context->logical_gpu, &create_info, nullptr, &module); | |
| if (result != VK_SUCCESS) { | |
| // @TODO(colby): do error handling | |
| return false; | |
| } | |
| return true; | |
| } | |
| void free_shader(Shader* shader) { | |
| if (shader->module != VK_NULL_HANDLE) vkDestroyShaderModule(g_render_context->logical_gpu, shader->module, nullptr); | |
| shader->module = VK_NULL_HANDLE; | |
| } | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment