Created
May 26, 2019 19:48
-
-
Save aolo2/e363dab33c38149440b7af285c54c917 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
| #define GLFW_INCLUDE_VULKAN | |
| #define NUM_SAMPLES VK_SAMPLE_COUNT_1_BIT | |
| #define NUM_DESCRIPTOR_SETS 1 | |
| #define NUM_SHADER_STAGES 2 | |
| #define NUM_VERT_ATTRIBUTES 2 | |
| #define NUM_VIEWPORTS 1 | |
| #define NUM_SCISSORS NUM_VIEWPORTS | |
| #define FENCE_TIMEOUT 100000000 | |
| #include "common.h" | |
| #include "linmath.h" | |
| #include "data/cube.h" | |
| #include <GLFW/glfw3.h> | |
| #include <xcb/xcb.h> | |
| struct swapchain_buffer { | |
| VkImage image; | |
| VkImageView view; | |
| }; | |
| struct depth_buffer { | |
| VkFormat format; | |
| VkImage image; | |
| VkDeviceMemory mem; | |
| VkImageView view; | |
| }; | |
| struct uniform_buffer { | |
| VkBuffer buf; | |
| VkDeviceMemory mem; | |
| VkDescriptorBufferInfo buffer_info; | |
| }; | |
| struct vertex_buffer { | |
| VkBuffer buf; | |
| VkDeviceMemory mem; | |
| VkDescriptorBufferInfo buffer_info; | |
| }; | |
| static struct { | |
| VkInstance instance; | |
| VkApplicationInfo application_info; | |
| VkInstanceCreateInfo instance_create_info; | |
| VkPhysicalDevice *gpus; | |
| VkDeviceQueueCreateInfo queue_info; | |
| VkQueueFamilyProperties *queue_properties; | |
| VkDeviceCreateInfo device_info; | |
| VkDevice device; | |
| VkCommandPool cbp; | |
| VkCommandPoolCreateInfo cbp_info; | |
| VkCommandBuffer command_buffer; | |
| VkXcbSurfaceCreateInfoKHR surface_create_info; | |
| VkSurfaceKHR surface; | |
| VkSwapchainCreateInfoKHR swapchain_create_info; | |
| VkFormat format; | |
| VkSwapchainKHR swapchain; | |
| VkImage *swapchain_images; | |
| struct swapchain_buffer *buffers; | |
| struct depth_buffer depth; | |
| struct uniform_buffer uniform; | |
| struct vertex_buffer vertex; | |
| VkPhysicalDeviceProperties gpu_props; | |
| VkPhysicalDeviceMemoryProperties memory_properties; | |
| VkDescriptorSetLayout descriptor_layout[NUM_DESCRIPTOR_SETS]; | |
| VkPipelineLayout pipeline_layout; | |
| VkDescriptorPool descriptor_pool; | |
| VkDescriptorSet descriptor_set[NUM_DESCRIPTOR_SETS]; | |
| VkRenderPass render_pass; | |
| VkPipelineShaderStageCreateInfo shader_stages[NUM_SHADER_STAGES]; | |
| VkFramebuffer *framebuffers; | |
| VkVertexInputBindingDescription vi_binding; | |
| VkVertexInputAttributeDescription vi_attribs[NUM_VERT_ATTRIBUTES]; | |
| VkPipeline pipeline; | |
| VkViewport viewport; | |
| VkRect2D scissor; | |
| VkQueue graphics_queue; | |
| VkQueue present_queue; | |
| xcb_connection_t *connection; | |
| xcb_screen_t *screen; | |
| xcb_window_t window; | |
| xcb_intern_atom_reply_t *atom_wm_delete_window; | |
| mat4x4 projection; | |
| mat4x4 view; | |
| mat4x4 model; | |
| mat4x4 clip; | |
| mat4x4 mvp; | |
| u32 current_buffer; | |
| u32 swapchain_image_count; | |
| u32 graphics_queue_family_index; | |
| u32 present_queue_family_index; | |
| u32 queue_family_count; | |
| u32 gpu_count; | |
| f32 queue_priorities[1]; | |
| const char **instance_extension_names; | |
| const char **device_extension_names; | |
| u32 width; | |
| u32 height; | |
| } data; | |
| static u32 * | |
| get_binary(const char *filename, u32 *size) | |
| { | |
| FILE *file = fopen(filename, "rb"); | |
| if (!file) { | |
| printf("[ERROR] File could not be opened\n"); | |
| return(NULL); | |
| } | |
| fseek(file, 0L, SEEK_END); | |
| *size = ftell(file); | |
| rewind(file); | |
| // NOTE: size % sizeof(u32) is always zero | |
| u32 *buffer = (u32 *) malloc(*size); | |
| fread((u8 *) buffer, *size, 1, file); | |
| *size /= sizeof(u32); | |
| fclose(file); | |
| return(buffer); | |
| } | |
| static void | |
| create_xcb_window(u32 width, u32 height) | |
| { | |
| // init connection | |
| s32 screen; | |
| const xcb_setup_t *setup; | |
| xcb_screen_iterator_t si; | |
| data.connection = xcb_connect(NULL, &screen); | |
| setup = xcb_get_setup(data.connection); | |
| si = xcb_setup_roots_iterator(setup); | |
| while (screen-- > 0) { | |
| xcb_screen_next(&si); | |
| } | |
| data.screen = si.data; | |
| // init window | |
| u32 value_mask; | |
| u32 value_list[32]; | |
| data.width = width; | |
| data.height = height; | |
| data.window = xcb_generate_id(data.connection); | |
| value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; | |
| value_list[0] = data.screen->black_pixel; | |
| value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE; | |
| xcb_create_window(data.connection, XCB_COPY_FROM_PARENT, data.window, data.screen->root, 0, 0, data.width, data.height, 0, | |
| XCB_WINDOW_CLASS_INPUT_OUTPUT, data.screen->root_visual, value_mask, value_list); | |
| xcb_intern_atom_cookie_t cookie = xcb_intern_atom(data.connection, 1, 12, "WM_PROTOCOLS"); | |
| xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(data.connection, cookie, 0); | |
| xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(data.connection, 0, 16, "WM_DELETE_WINDOW"); | |
| data.atom_wm_delete_window = xcb_intern_atom_reply(data.connection, cookie2, 0); | |
| xcb_change_property(data.connection, XCB_PROP_MODE_REPLACE, data.window, (*reply).atom, 4, 32, 1, | |
| &(*data.atom_wm_delete_window).atom); | |
| xcb_map_window(data.connection, data.window); | |
| const u32 coords[2] = {100, 100}; | |
| xcb_configure_window(data.connection, data.window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords); | |
| xcb_flush(data.connection); | |
| xcb_generic_event_t *e; | |
| while ((e = xcb_wait_for_event(data.connection))) { | |
| if ((e->response_type & ~0x80) == XCB_EXPOSE) { | |
| break; | |
| } | |
| } | |
| } | |
| static bool | |
| find_graphics_and_present_queues() | |
| { | |
| VkBool32 *supports_present = malloc(data.queue_family_count * sizeof(VkBool32)); | |
| data.graphics_queue_family_index = UINT32_MAX; | |
| data.present_queue_family_index = UINT32_MAX; | |
| for (u32 i = 0; i < data.queue_family_count; ++i) { | |
| vkGetPhysicalDeviceSurfaceSupportKHR(data.gpus[0], i, data.surface, supports_present + i); | |
| } | |
| for (u32 i = 0; i < data.queue_family_count; ++i) { | |
| if ((data.queue_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) { | |
| if (data.graphics_queue_family_index == UINT32_MAX) { | |
| data.graphics_queue_family_index = i; | |
| } | |
| if (supports_present[i] == VK_TRUE) { | |
| data.graphics_queue_family_index = i; | |
| data.present_queue_family_index = i; | |
| break; | |
| } | |
| } | |
| } | |
| if (data.present_queue_family_index == UINT32_MAX) { | |
| for (u32 i = 0; i < data.queue_family_count; ++i) { | |
| if (supports_present[i] == VK_TRUE) { | |
| data.present_queue_family_index = i; | |
| break; | |
| } | |
| } | |
| } | |
| return(data.present_queue_family_index != UINT32_MAX && | |
| data.graphics_queue_family_index != UINT32_MAX); | |
| } | |
| static bool | |
| memory_type_from_properties(u32 type_bits, VkFlags requirements_mask, u32 *type_index) { | |
| for (u32 i = 0; i < data.memory_properties.memoryTypeCount; ++i) { | |
| if ((type_bits & 1) == 1) { | |
| if ((data.memory_properties.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) { | |
| *type_index = i; | |
| return(true); | |
| } | |
| } | |
| type_bits = type_bits >> 1; | |
| } | |
| return(false); | |
| } | |
| s32 | |
| main(void) | |
| { | |
| // 01. Init instance | |
| { | |
| u32 extension_count = 2; | |
| data.application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; | |
| data.application_info.pNext = NULL; | |
| data.application_info.pApplicationName = "thesis"; | |
| data.application_info.applicationVersion = 1; | |
| data.application_info.pEngineName = "thesis"; | |
| data.application_info.engineVersion = 1; | |
| data.application_info.apiVersion = VK_API_VERSION_1_0; | |
| ASSERT(data.instance_extension_names = malloc(extension_count * sizeof(char *))); | |
| ASSERT(data.instance_extension_names[0] = strdup(VK_KHR_SURFACE_EXTENSION_NAME)); | |
| ASSERT(data.instance_extension_names[1] = strdup(VK_KHR_XCB_SURFACE_EXTENSION_NAME)); | |
| data.instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; | |
| data.instance_create_info.pNext = NULL; | |
| data.instance_create_info.flags = 0; | |
| data.instance_create_info.pApplicationInfo = &data.application_info; | |
| data.instance_create_info.ppEnabledExtensionNames = data.instance_extension_names; | |
| data.instance_create_info.enabledExtensionCount = extension_count; | |
| data.instance_create_info.enabledLayerCount = 0; | |
| data.instance_create_info.ppEnabledLayerNames = NULL; | |
| ASSERT_VK(vkCreateInstance(&data.instance_create_info, NULL, &data.instance)); | |
| } // End of init instance | |
| // 02. Enumerate devices | |
| { | |
| ASSERT_VK(vkEnumeratePhysicalDevices(data.instance, &data.gpu_count, NULL)); | |
| ASSERT(data.gpu_count); | |
| ASSERT(data.gpus = malloc(data.gpu_count * sizeof(VkPhysicalDevice))); | |
| ASSERT_VK(vkEnumeratePhysicalDevices(data.instance, &data.gpu_count, data.gpus)); | |
| } // End of enumerate devices | |
| // Init surface and window | |
| { | |
| create_xcb_window(800, 600); // this inits data.connection and data.window | |
| data.surface_create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; | |
| data.surface_create_info.pNext = NULL; | |
| data.surface_create_info.connection = data.connection; | |
| data.surface_create_info.window = data.window; | |
| data.format = VK_FORMAT_B8G8R8A8_UNORM; // TODO | |
| ASSERT_VK(vkCreateXcbSurfaceKHR(data.instance, &data.surface_create_info, NULL, &data.surface)); | |
| } // End of init surface and window | |
| // 03. Init device | |
| { | |
| u32 extension_count = 1; | |
| vkGetPhysicalDeviceQueueFamilyProperties(data.gpus[0], &data.queue_family_count, NULL); | |
| ASSERT(data.queue_family_count); | |
| ASSERT(data.queue_properties = malloc(data.queue_family_count * sizeof(VkQueueFamilyProperties))); | |
| vkGetPhysicalDeviceQueueFamilyProperties(data.gpus[0], &data.queue_family_count, data.queue_properties); | |
| ASSERT(find_graphics_and_present_queues()); | |
| data.queue_priorities[0] = 0.0f; | |
| data.queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; | |
| data.queue_info.pNext = NULL; | |
| data.queue_info.queueCount = 1; | |
| data.queue_info.pQueuePriorities = data.queue_priorities; | |
| ASSERT(data.device_extension_names = malloc(extension_count * sizeof(char *))); | |
| ASSERT(data.device_extension_names[0] = strdup(VK_KHR_SWAPCHAIN_EXTENSION_NAME)); | |
| data.device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; | |
| data.device_info.pNext = NULL; | |
| data.device_info.queueCreateInfoCount = 1; | |
| data.device_info.pQueueCreateInfos = &data.queue_info; | |
| data.device_info.ppEnabledExtensionNames = data.device_extension_names; | |
| data.device_info.enabledExtensionCount = 1; | |
| data.device_info.enabledLayerCount = 0; | |
| data.device_info.ppEnabledLayerNames = NULL; | |
| data.device_info.pEnabledFeatures = NULL; | |
| ASSERT_VK(vkCreateDevice(data.gpus[0], &data.device_info, NULL, &data.device)); | |
| } // End of init device | |
| // 04. Init command buffer | |
| { | |
| VkCommandBufferAllocateInfo cmd; | |
| data.cbp_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; | |
| data.cbp_info.pNext = NULL; | |
| data.cbp_info.queueFamilyIndex = data.queue_info.queueFamilyIndex; | |
| data.cbp_info.flags = 0; | |
| ASSERT_VK(vkCreateCommandPool(data.device, &data.cbp_info, NULL, &data.cbp)); | |
| cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; | |
| cmd.pNext = NULL; | |
| cmd.commandPool = data.cbp; | |
| cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; | |
| cmd.commandBufferCount = 1; | |
| ASSERT_VK(vkAllocateCommandBuffers(data.device, &cmd, &data.command_buffer)); | |
| #if 1 | |
| VkCommandBufferBeginInfo cmd_buf_info; | |
| cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; | |
| cmd_buf_info.pNext = NULL; | |
| cmd_buf_info.flags = 0; | |
| cmd_buf_info.pInheritanceInfo = NULL; | |
| ASSERT_VK(vkBeginCommandBuffer(data.command_buffer, &cmd_buf_info)); | |
| #endif | |
| vkGetDeviceQueue(data.device, data.graphics_queue_family_index, 0, &data.graphics_queue); | |
| if (data.graphics_queue_family_index == data.present_queue_family_index) { | |
| data.present_queue = data.graphics_queue; | |
| } else { | |
| vkGetDeviceQueue(data.device, data.present_queue_family_index, 0, &data.present_queue); | |
| } | |
| } // End of init command buffer | |
| // 05. Init swapchain | |
| { | |
| u32 present_mode_count; | |
| VkSurfaceCapabilitiesKHR capabilities; | |
| VkPresentModeKHR *present_modes; | |
| VkExtent2D swapchain_extent; | |
| VkSurfaceTransformFlagBitsKHR pre_transform; | |
| VkCompositeAlphaFlagBitsKHR composite_alpha; | |
| VkCompositeAlphaFlagBitsKHR composite_alpha_flags[4] = { | |
| VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, | |
| VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, | |
| VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, | |
| VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, | |
| }; | |
| u32 queue_family_indices[2] = { | |
| (u32) data.graphics_queue_family_index, | |
| (u32) data.present_queue_family_index | |
| }; | |
| ASSERT_VK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(data.gpus[0], data.surface, &capabilities)); | |
| ASSERT_VK(vkGetPhysicalDeviceSurfacePresentModesKHR(data.gpus[0], data.surface, &present_mode_count, NULL)); | |
| ASSERT(present_modes = malloc(present_mode_count * sizeof(VkPresentModeKHR))); | |
| ASSERT_VK(vkGetPhysicalDeviceSurfacePresentModesKHR(data.gpus[0], data.surface, &present_mode_count, present_modes)); | |
| if (capabilities.currentExtent.width == 0xFFFFFFFF) { | |
| swapchain_extent.width = data.width; | |
| swapchain_extent.height = data.height; | |
| if (swapchain_extent.width < capabilities.minImageExtent.width) { | |
| swapchain_extent.width = capabilities.minImageExtent.width; | |
| } else if (swapchain_extent.width > capabilities.maxImageExtent.width) { | |
| swapchain_extent.width = capabilities.maxImageExtent.width; | |
| } | |
| if (swapchain_extent.height < capabilities.minImageExtent.height) { | |
| swapchain_extent.height = capabilities.minImageExtent.height; | |
| } else if (swapchain_extent.height > capabilities.maxImageExtent.height) { | |
| swapchain_extent.height = capabilities.maxImageExtent.height; | |
| } | |
| } else { | |
| swapchain_extent= capabilities.currentExtent; | |
| } | |
| if (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { | |
| pre_transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; | |
| } else { | |
| pre_transform = capabilities.currentTransform; | |
| } | |
| composite_alpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; | |
| for (u32 i = 0; i < 4; ++i) { | |
| if (capabilities.supportedCompositeAlpha & composite_alpha_flags[i]) { | |
| composite_alpha = composite_alpha_flags[i]; | |
| break; | |
| } | |
| } | |
| data.swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; | |
| data.swapchain_create_info.pNext = NULL; | |
| data.swapchain_create_info.surface = data.surface; | |
| data.swapchain_create_info.minImageCount = capabilities.minImageCount; | |
| data.swapchain_create_info.imageFormat = data.format; | |
| data.swapchain_create_info.imageExtent.width = swapchain_extent.width; | |
| data.swapchain_create_info.imageExtent.height = swapchain_extent.height; | |
| data.swapchain_create_info.preTransform = pre_transform; | |
| data.swapchain_create_info.compositeAlpha = composite_alpha; | |
| data.swapchain_create_info.imageArrayLayers = 1; | |
| data.swapchain_create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; | |
| data.swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; | |
| data.swapchain_create_info.clipped = true; | |
| data.swapchain_create_info.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; | |
| data.swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; | |
| data.swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; | |
| data.swapchain_create_info.queueFamilyIndexCount = 0; | |
| data.swapchain_create_info.pQueueFamilyIndices = NULL; | |
| if (data.graphics_queue_family_index != data.present_queue_family_index) { | |
| data.swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; | |
| data.swapchain_create_info.queueFamilyIndexCount = 2; | |
| data.swapchain_create_info.pQueueFamilyIndices = queue_family_indices; | |
| } | |
| ASSERT_VK(vkCreateSwapchainKHR(data.device, &data.swapchain_create_info, NULL, &data.swapchain)); | |
| ASSERT_VK(vkGetSwapchainImagesKHR(data.device, data.swapchain, &data.swapchain_image_count, NULL)); | |
| ASSERT(data.swapchain_images = malloc(data.swapchain_image_count * sizeof(VkImage))); | |
| ASSERT_VK(vkGetSwapchainImagesKHR(data.device, data.swapchain, &data.swapchain_image_count, data.swapchain_images)); | |
| ASSERT(data.buffers = malloc(data.swapchain_image_count * sizeof(struct swapchain_buffer))); | |
| for (u32 i = 0; i < data.swapchain_image_count; ++i) { | |
| VkImageViewCreateInfo color_image_view; | |
| data.buffers[i].image = data.swapchain_images[i]; | |
| color_image_view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; | |
| color_image_view.pNext = NULL; | |
| color_image_view.flags = 0; | |
| color_image_view.image = data.buffers[i].image; | |
| color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D; | |
| color_image_view.format = data.format; | |
| color_image_view.components.r = VK_COMPONENT_SWIZZLE_R; | |
| color_image_view.components.g = VK_COMPONENT_SWIZZLE_G; | |
| color_image_view.components.b = VK_COMPONENT_SWIZZLE_B; | |
| color_image_view.components.a = VK_COMPONENT_SWIZZLE_A; | |
| color_image_view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | |
| color_image_view.subresourceRange.baseMipLevel = 0; | |
| color_image_view.subresourceRange.levelCount = 1; | |
| color_image_view.subresourceRange.baseArrayLayer = 0; | |
| color_image_view.subresourceRange.layerCount = 1; | |
| ASSERT_VK(vkCreateImageView(data.device, &color_image_view, NULL, &data.buffers[i].view)); | |
| } | |
| } // End of init swapchain | |
| // 06. Create a depth buffer | |
| { | |
| VkImageCreateInfo image_info; | |
| VkFormatProperties properties; | |
| VkMemoryAllocateInfo mem_alloc; | |
| VkImageViewCreateInfo view_info; | |
| VkMemoryRequirements mem_reqs; | |
| VkFormat depth_format = VK_FORMAT_D16_UNORM; | |
| vkGetPhysicalDeviceFormatProperties(data.gpus[0], depth_format, &properties); | |
| if (properties.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { | |
| image_info.tiling = VK_IMAGE_TILING_LINEAR; | |
| } else if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { | |
| image_info.tiling = VK_IMAGE_TILING_OPTIMAL; | |
| } else { | |
| printf("[ERROR] VK_FORMAT_D16_UNORM Unsupported.\n"); | |
| exit(1); | |
| } | |
| image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; | |
| image_info.pNext = NULL; | |
| image_info.imageType = VK_IMAGE_TYPE_2D; | |
| image_info.format = VK_FORMAT_D16_UNORM; | |
| image_info.extent.width = data.width; | |
| image_info.extent.height = data.height; | |
| image_info.extent.depth = 1; | |
| image_info.mipLevels = 1; | |
| image_info.arrayLayers = 1; | |
| image_info.samples = NUM_SAMPLES; | |
| image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | |
| image_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; | |
| image_info.queueFamilyIndexCount = 0; | |
| image_info.pQueueFamilyIndices = NULL; | |
| image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | |
| image_info.flags = 0; | |
| mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | |
| mem_alloc.pNext = NULL; | |
| mem_alloc.allocationSize = 0; | |
| mem_alloc.memoryTypeIndex = 0; | |
| view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; | |
| view_info.pNext = NULL; | |
| view_info.image = VK_NULL_HANDLE; | |
| view_info.format = depth_format; | |
| view_info.components.r = VK_COMPONENT_SWIZZLE_R; | |
| view_info.components.g = VK_COMPONENT_SWIZZLE_G; | |
| view_info.components.b = VK_COMPONENT_SWIZZLE_B; | |
| view_info.components.a = VK_COMPONENT_SWIZZLE_A; | |
| view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; | |
| view_info.subresourceRange.baseMipLevel = 0; | |
| view_info.subresourceRange.levelCount = 1; | |
| view_info.subresourceRange.baseArrayLayer = 0; | |
| view_info.subresourceRange.layerCount = 1; | |
| view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; | |
| view_info.flags = 0; | |
| data.depth.format = depth_format; | |
| ASSERT_VK(vkCreateImage(data.device, &image_info, NULL, &data.depth.image)); | |
| vkGetImageMemoryRequirements(data.device, data.depth.image, &mem_reqs); | |
| vkGetPhysicalDeviceMemoryProperties(data.gpus[0], &data.memory_properties); | |
| vkGetPhysicalDeviceProperties(data.gpus[0], &data.gpu_props); | |
| mem_alloc.allocationSize = mem_reqs.size; | |
| ASSERT(memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex)); | |
| ASSERT_VK(vkAllocateMemory(data.device, &mem_alloc, NULL, &data.depth.mem)); | |
| ASSERT_VK(vkBindImageMemory(data.device, data.depth.image, data.depth.mem, 0)); | |
| view_info.image = data.depth.image; | |
| ASSERT_VK(vkCreateImageView(data.device, &view_info, NULL, &data.depth.view)); | |
| ASSERT_VK(vkCreateImage(data.device, &image_info, NULL, &data.depth.image)); | |
| } // End of create a depth buffer | |
| // 07. Create a uniform buffer | |
| { | |
| u8 *buffer_data; | |
| VkBufferCreateInfo buf_info; | |
| VkMemoryRequirements mem_reqs; | |
| VkMemoryAllocateInfo alloc_info; | |
| vec3 eye = { -5, 3, -10 }; | |
| vec3 center = { 0, 0, 0 }; | |
| vec3 up = { 0, -1, 0 }; | |
| mat4x4_perspective(data.projection, 0.785f, (f32) data.width / (f32) data.height, 0.1f, 100.f); | |
| mat4x4_look_at(data.view, eye, center, up); | |
| mat4x4_identity(data.model); | |
| mat4x4_identity(data.clip); | |
| data.clip[1][1] = -1.0f; | |
| data.clip[2][2] = 0.5f; | |
| data.clip[2][3] = 0.5f; | |
| mat4x4_mul(data.mvp, data.clip, data.projection); | |
| mat4x4_mul(data.mvp, data.mvp, data.view); | |
| mat4x4_mul(data.mvp, data.mvp, data.model); | |
| buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; | |
| buf_info.pNext = NULL; | |
| buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; | |
| buf_info.size = sizeof(data.mvp); | |
| buf_info.queueFamilyIndexCount = 0; | |
| buf_info.pQueueFamilyIndices = NULL; | |
| buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | |
| buf_info.flags = 0; | |
| ASSERT_VK(vkCreateBuffer(data.device, &buf_info, NULL, &data.uniform.buf)); | |
| vkGetBufferMemoryRequirements(data.device, data.uniform.buf, &mem_reqs); | |
| alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | |
| alloc_info.pNext = NULL; | |
| alloc_info.memoryTypeIndex = 0; | |
| alloc_info.allocationSize = mem_reqs.size; | |
| ASSERT(memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &alloc_info.memoryTypeIndex)); | |
| ASSERT_VK(vkAllocateMemory(data.device, &alloc_info, NULL, &(data.uniform.mem))); | |
| ASSERT_VK(vkMapMemory(data.device, data.uniform.mem, 0, mem_reqs.size, 0, (void **) &buffer_data)); | |
| memcpy(buffer_data, data.mvp, sizeof(data.mvp)); | |
| vkUnmapMemory(data.device, data.uniform.mem); | |
| ASSERT_VK(vkBindBufferMemory(data.device, data.uniform.buf, data.uniform.mem, 0)); | |
| data.uniform.buffer_info.buffer = data.uniform.buf; | |
| data.uniform.buffer_info.offset = 0; | |
| data.uniform.buffer_info.range = sizeof(data.mvp); | |
| } // End of create a uniform buffer | |
| // 08. Init pipeline layout | |
| { | |
| VkDescriptorSetLayoutBinding layout_binding; | |
| VkDescriptorSetLayoutCreateInfo descriptor_layout; | |
| VkPipelineLayoutCreateInfo pipeline_layout_create_info; | |
| layout_binding.binding = 0; | |
| layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; | |
| layout_binding.descriptorCount = 1; | |
| layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; | |
| layout_binding.pImmutableSamplers = NULL; | |
| descriptor_layout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; | |
| descriptor_layout.pNext = NULL; | |
| descriptor_layout.bindingCount = 1; | |
| descriptor_layout.pBindings = &layout_binding; | |
| ASSERT_VK(vkCreateDescriptorSetLayout(data.device, &descriptor_layout, NULL, data.descriptor_layout)); | |
| pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; | |
| pipeline_layout_create_info.pNext = NULL; | |
| pipeline_layout_create_info.pushConstantRangeCount = 0; | |
| pipeline_layout_create_info.pPushConstantRanges = NULL; | |
| pipeline_layout_create_info.setLayoutCount = NUM_DESCRIPTOR_SETS; | |
| pipeline_layout_create_info.pSetLayouts = data.descriptor_layout; | |
| ASSERT_VK(vkCreatePipelineLayout(data.device, &pipeline_layout_create_info, NULL, &data.pipeline_layout)); | |
| } // End of init pipeline layout | |
| // 09. Init a descriptor set | |
| { | |
| VkWriteDescriptorSet writes[1]; | |
| VkDescriptorPoolSize type_count[1]; | |
| VkDescriptorSetAllocateInfo alloc_info[1]; | |
| VkDescriptorPoolCreateInfo descriptor_pool; | |
| type_count[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; | |
| type_count[0].descriptorCount = 1; | |
| descriptor_pool.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; | |
| descriptor_pool.pNext = NULL; | |
| descriptor_pool.maxSets = 1; | |
| descriptor_pool.poolSizeCount = 1; | |
| descriptor_pool.pPoolSizes = type_count; | |
| ASSERT_VK(vkCreateDescriptorPool(data.device, &descriptor_pool, NULL, &data.descriptor_pool)); | |
| alloc_info[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; | |
| alloc_info[0].pNext = NULL; | |
| alloc_info[0].descriptorPool = data.descriptor_pool; | |
| alloc_info[0].descriptorSetCount = NUM_DESCRIPTOR_SETS; | |
| alloc_info[0].pSetLayouts = data.descriptor_layout; | |
| ASSERT_VK(vkAllocateDescriptorSets(data.device, alloc_info, data.descriptor_set)); | |
| writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; | |
| writes[0].pNext = NULL; | |
| writes[0].dstSet = data.descriptor_set[0]; | |
| writes[0].descriptorCount = 1; | |
| writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; | |
| writes[0].pBufferInfo = &data.uniform.buffer_info; | |
| writes[0].dstArrayElement = 0; | |
| writes[0].dstBinding = 0; | |
| vkUpdateDescriptorSets(data.device, 1, writes, 0, NULL); | |
| } // End of init a descriptor set | |
| // 10. Init a render pass | |
| { | |
| VkSemaphore image_acquired_semaphore; | |
| VkSemaphoreCreateInfo image_acquired_semaphore_create_info; | |
| VkAttachmentDescription attachments[2]; | |
| VkAttachmentReference color_reference; | |
| VkAttachmentReference depth_reference; | |
| VkSubpassDescription subpass; | |
| VkRenderPassCreateInfo rp_info; | |
| image_acquired_semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; | |
| image_acquired_semaphore_create_info.pNext = NULL; | |
| image_acquired_semaphore_create_info.flags = 0; | |
| ASSERT_VK(vkCreateSemaphore(data.device, &image_acquired_semaphore_create_info, NULL, &image_acquired_semaphore)); | |
| ASSERT_VK(vkAcquireNextImageKHR(data.device, data.swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &data.current_buffer)); | |
| attachments[0].format = data.format; | |
| attachments[0].samples = NUM_SAMPLES; | |
| attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; | |
| attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; | |
| attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; | |
| attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; | |
| attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | |
| attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; | |
| attachments[0].flags = 0; | |
| attachments[1].format = data.depth.format; | |
| attachments[1].samples = NUM_SAMPLES; | |
| attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; | |
| attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; | |
| attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; | |
| attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; | |
| attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | |
| attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; | |
| attachments[1].flags = 0; | |
| color_reference.attachment = 0; | |
| color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | |
| depth_reference.attachment = 1; | |
| depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; | |
| subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; | |
| subpass.flags = 0; | |
| subpass.inputAttachmentCount = 0; | |
| subpass.pInputAttachments = NULL; | |
| subpass.colorAttachmentCount = 1; | |
| subpass.pColorAttachments = &color_reference; | |
| subpass.pResolveAttachments = NULL; | |
| subpass.pDepthStencilAttachment = &depth_reference; | |
| subpass.preserveAttachmentCount = 0; | |
| subpass.pPreserveAttachments = NULL; | |
| rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; | |
| rp_info.pNext = NULL; | |
| rp_info.attachmentCount = 2; | |
| rp_info.pAttachments = attachments; | |
| rp_info.subpassCount = 1; | |
| rp_info.pSubpasses = &subpass; | |
| rp_info.dependencyCount = 0; | |
| rp_info.pDependencies = NULL; | |
| ASSERT_VK(vkCreateRenderPass(data.device, &rp_info, NULL, &data.render_pass)); | |
| } // End of init a render pass | |
| // 11. Init shaders | |
| { | |
| VkShaderModuleCreateInfo module_create_info; | |
| u32 *vs_words, *fs_words; | |
| u32 vs_size, fs_size; | |
| vs_words = get_binary("shaders/sample.vert.spv", &vs_size); | |
| fs_words = get_binary("shaders/sample.frag.spv", &fs_size); | |
| data.shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; | |
| data.shader_stages[0].pNext = NULL; | |
| data.shader_stages[0].pSpecializationInfo = NULL; | |
| data.shader_stages[0].flags = 0; | |
| data.shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; | |
| data.shader_stages[0].pName = "main"; | |
| module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; | |
| module_create_info.pNext = NULL; | |
| module_create_info.flags = 0; | |
| module_create_info.codeSize = vs_size * sizeof(u32); | |
| module_create_info.pCode = vs_words; | |
| ASSERT_VK(vkCreateShaderModule(data.device, &module_create_info, NULL, &data.shader_stages[0].module)); | |
| data.shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; | |
| data.shader_stages[1].pNext = NULL; | |
| data.shader_stages[1].pSpecializationInfo = NULL; | |
| data.shader_stages[1].flags = 0; | |
| data.shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; | |
| data.shader_stages[1].pName = "main"; | |
| module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; | |
| module_create_info.pNext = NULL; | |
| module_create_info.flags = 0; | |
| module_create_info.codeSize = fs_size * sizeof(u32); | |
| module_create_info.pCode = fs_words; | |
| ASSERT_VK(vkCreateShaderModule(data.device, &module_create_info, NULL, &data.shader_stages[1].module)); | |
| } // End of init shaders | |
| // 12. Init framebuffers | |
| { | |
| VkFramebufferCreateInfo fb_info; | |
| VkImageView attachments[2]; | |
| attachments[1] = data.depth.view; | |
| fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; | |
| fb_info.pNext = NULL; | |
| fb_info.renderPass = data.render_pass; | |
| fb_info.attachmentCount = 2; | |
| fb_info.pAttachments = attachments; | |
| fb_info.width = data.width; | |
| fb_info.height = data.height; | |
| fb_info.layers = 1; | |
| ASSERT(data.framebuffers = malloc(data.swapchain_image_count * sizeof(VkFramebuffer))); | |
| for (u32 i = 0; i < data.swapchain_image_count; ++i) { | |
| attachments[0] = data.buffers[i].view; | |
| ASSERT_VK(vkCreateFramebuffer(data.device, &fb_info, NULL, &data.framebuffers[i])); | |
| } | |
| } // End of init framebuffers | |
| // 13. Init vertex buffer | |
| { | |
| u8 *vertex_data; | |
| VkBufferCreateInfo buf_info; | |
| VkMemoryRequirements mem_reqs; | |
| VkMemoryAllocateInfo alloc_info; | |
| VkSemaphore image_acquired_semaphore; | |
| VkRenderPassBeginInfo rp_begin; | |
| VkSemaphoreCreateInfo image_acquired_semaphore_create_info; | |
| const VkDeviceSize offsets[1] = { 0 }; | |
| VkClearValue clear_values[2]; | |
| buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; | |
| buf_info.pNext = NULL; | |
| buf_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; | |
| buf_info.size = sizeof(g_vb_solid_face_colors_Data); | |
| buf_info.queueFamilyIndexCount = 0; | |
| buf_info.pQueueFamilyIndices = NULL; | |
| buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | |
| buf_info.flags = 0; | |
| ASSERT_VK(vkCreateBuffer(data.device, &buf_info, NULL, &data.vertex.buf)); | |
| vkGetBufferMemoryRequirements(data.device, data.vertex.buf, &mem_reqs); | |
| alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | |
| alloc_info.pNext = NULL; | |
| alloc_info.memoryTypeIndex = 0; | |
| alloc_info.allocationSize = mem_reqs.size; | |
| ASSERT(memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &alloc_info.memoryTypeIndex)); | |
| ASSERT_VK(vkAllocateMemory(data.device, &alloc_info, NULL, &(data.vertex.mem))); | |
| ASSERT_VK(vkMapMemory(data.device, data.vertex.mem, 0, mem_reqs.size, 0, (void **) &vertex_data)); | |
| memcpy(vertex_data, g_vb_solid_face_colors_Data, sizeof(g_vb_solid_face_colors_Data)); | |
| vkUnmapMemory(data.device, data.vertex.mem); | |
| ASSERT_VK(vkBindBufferMemory(data.device, data.vertex.buf, data.vertex.mem, 0)); | |
| data.vi_binding.binding = 0; | |
| data.vi_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; | |
| data.vi_binding.stride = sizeof(g_vb_solid_face_colors_Data[0]); | |
| data.vi_attribs[0].binding = 0; | |
| data.vi_attribs[0].location = 0; | |
| data.vi_attribs[0].format = VK_FORMAT_R32G32B32A32_SFLOAT; | |
| data.vi_attribs[0].offset = 0; | |
| data.vi_attribs[1].binding = 0; | |
| data.vi_attribs[1].location = 1; | |
| data.vi_attribs[1].format = VK_FORMAT_R32G32B32A32_SFLOAT; | |
| data.vi_attribs[1].offset = 16; | |
| clear_values[0].color.float32[0] = 0.0f; | |
| clear_values[0].color.float32[1] = 0.0f; | |
| clear_values[0].color.float32[2] = 0.0f; | |
| clear_values[0].color.float32[3] = 0.0f; | |
| clear_values[1].depthStencil.depth = 1.0f; | |
| clear_values[1].depthStencil.stencil = 0; | |
| image_acquired_semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; | |
| image_acquired_semaphore_create_info.pNext = NULL; | |
| image_acquired_semaphore_create_info.flags = 0; | |
| ASSERT_VK(vkCreateSemaphore(data.device, &image_acquired_semaphore_create_info, NULL, &image_acquired_semaphore)); | |
| ASSERT_VK(vkAcquireNextImageKHR(data.device, data.swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &data.current_buffer)); | |
| rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; | |
| rp_begin.pNext = NULL; | |
| rp_begin.renderPass = data.render_pass; | |
| rp_begin.framebuffer = data.framebuffers[data.current_buffer]; | |
| rp_begin.renderArea.offset.x = 0; | |
| rp_begin.renderArea.offset.y = 0; | |
| rp_begin.renderArea.extent.width = data.width; | |
| rp_begin.renderArea.extent.height = data.height; | |
| rp_begin.clearValueCount = 2; | |
| rp_begin.pClearValues = clear_values; | |
| vkCmdBeginRenderPass(data.command_buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); | |
| vkCmdBindVertexBuffers(data.command_buffer, 0, 1, &data.vertex.buf, offsets); | |
| vkCmdEndRenderPass(data.command_buffer); | |
| } // End of init vertex buffer | |
| // 14. Init pipeline | |
| { | |
| VkPipelineDynamicStateCreateInfo dynamic_state; | |
| VkDynamicState dynamic_state_enables[VK_DYNAMIC_STATE_RANGE_SIZE]; | |
| VkPipelineVertexInputStateCreateInfo vi; | |
| VkPipelineInputAssemblyStateCreateInfo ia; | |
| VkPipelineRasterizationStateCreateInfo rs; | |
| VkPipelineColorBlendStateCreateInfo cb; | |
| VkPipelineColorBlendAttachmentState att_state[1]; | |
| VkPipelineViewportStateCreateInfo vp; | |
| VkPipelineDepthStencilStateCreateInfo ds; | |
| VkPipelineMultisampleStateCreateInfo ms; | |
| VkGraphicsPipelineCreateInfo pipeline; | |
| memset(dynamic_state_enables, 0x00, sizeof(dynamic_state_enables)); | |
| dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; | |
| dynamic_state.pNext = NULL; | |
| dynamic_state.pDynamicStates = dynamic_state_enables; | |
| dynamic_state.dynamicStateCount = 0; | |
| vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; | |
| vi.pNext = NULL; | |
| vi.flags = 0; | |
| vi.vertexBindingDescriptionCount = 1; | |
| vi.pVertexBindingDescriptions = &data.vi_binding; | |
| vi.vertexAttributeDescriptionCount = 2; | |
| vi.pVertexAttributeDescriptions = data.vi_attribs; | |
| ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; | |
| ia.pNext = NULL; | |
| ia.flags = 0; | |
| ia.primitiveRestartEnable = VK_FALSE; | |
| ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; | |
| rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; | |
| rs.pNext = NULL; | |
| rs.flags = 0; | |
| rs.polygonMode = VK_POLYGON_MODE_FILL; | |
| rs.cullMode = VK_CULL_MODE_BACK_BIT; | |
| rs.frontFace = VK_FRONT_FACE_CLOCKWISE; | |
| rs.depthClampEnable = VK_FALSE; | |
| rs.rasterizerDiscardEnable = VK_FALSE; | |
| rs.depthBiasEnable = VK_FALSE; | |
| rs.depthBiasConstantFactor = 0; | |
| rs.depthBiasClamp = 0; | |
| rs.depthBiasSlopeFactor = 0; | |
| rs.lineWidth = 1.0f; | |
| cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; | |
| cb.pNext = NULL; | |
| cb.flags = 0; | |
| att_state[0].colorWriteMask = 0xF; | |
| att_state[0].blendEnable = VK_FALSE; | |
| att_state[0].alphaBlendOp = VK_BLEND_OP_ADD; | |
| att_state[0].colorBlendOp = VK_BLEND_OP_ADD; | |
| att_state[0].srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; | |
| att_state[0].dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; | |
| att_state[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; | |
| att_state[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; | |
| cb.attachmentCount = 1; | |
| cb.pAttachments = att_state; | |
| cb.logicOpEnable = VK_FALSE; | |
| cb.logicOp = VK_LOGIC_OP_NO_OP; | |
| cb.blendConstants[0] = 1.0f; | |
| cb.blendConstants[1] = 1.0f; | |
| cb.blendConstants[2] = 1.0f; | |
| cb.blendConstants[3] = 1.0f; | |
| vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; | |
| vp.pNext = NULL; | |
| vp.flags = 0; | |
| vp.viewportCount = NUM_VIEWPORTS; | |
| vp.scissorCount = NUM_SCISSORS; | |
| vp.pScissors = NULL; | |
| vp.pViewports = NULL; | |
| dynamic_state_enables[dynamic_state.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT; | |
| dynamic_state_enables[dynamic_state.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR; | |
| ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; | |
| ds.pNext = NULL; | |
| ds.flags = 0; | |
| ds.depthTestEnable = VK_TRUE; | |
| ds.depthWriteEnable = VK_TRUE; | |
| ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; | |
| ds.depthBoundsTestEnable = VK_FALSE; | |
| ds.minDepthBounds = 0; | |
| ds.maxDepthBounds = 0; | |
| ds.stencilTestEnable = VK_FALSE; | |
| ds.back.failOp = VK_STENCIL_OP_KEEP; | |
| ds.back.passOp = VK_STENCIL_OP_KEEP; | |
| ds.back.compareOp = VK_COMPARE_OP_ALWAYS; | |
| ds.back.compareMask = 0; | |
| ds.back.reference = 0; | |
| ds.back.depthFailOp = VK_STENCIL_OP_KEEP; | |
| ds.back.writeMask = 0; | |
| ds.front = ds.back; | |
| ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; | |
| ms.pNext = NULL; | |
| ms.flags = 0; | |
| ms.pSampleMask = NULL; | |
| ms.rasterizationSamples = NUM_SAMPLES; | |
| ms.sampleShadingEnable = VK_FALSE; | |
| ms.alphaToCoverageEnable = VK_FALSE; | |
| ms.alphaToOneEnable = VK_FALSE; | |
| ms.minSampleShading = 0.0; | |
| pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; | |
| pipeline.pNext = NULL; | |
| pipeline.layout = data.pipeline_layout; | |
| pipeline.basePipelineHandle = VK_NULL_HANDLE; | |
| pipeline.basePipelineIndex = 0; | |
| pipeline.flags = 0; | |
| pipeline.pVertexInputState = &vi; | |
| pipeline.pInputAssemblyState = &ia; | |
| pipeline.pRasterizationState = &rs; | |
| pipeline.pColorBlendState = &cb; | |
| pipeline.pTessellationState = NULL; | |
| pipeline.pMultisampleState = &ms; | |
| pipeline.pDynamicState = &dynamic_state; | |
| pipeline.pViewportState = &vp; | |
| pipeline.pDepthStencilState = &ds; | |
| pipeline.pStages = data.shader_stages; | |
| pipeline.stageCount = 2; | |
| pipeline.renderPass = data.render_pass; | |
| pipeline.subpass = 0; | |
| ASSERT_VK(vkCreateGraphicsPipelines(data.device, VK_NULL_HANDLE, 1, &pipeline, NULL, &data.pipeline)); | |
| } // End of init pipeline | |
| // 15. Draw cube | |
| { | |
| VkSemaphore image_acquired_semaphore; | |
| VkSemaphoreCreateInfo image_acquired_semaphore_create_info; | |
| VkRenderPassBeginInfo rp_begin; | |
| VkFenceCreateInfo fence_info; | |
| VkFence draw_fence; | |
| VkPipelineStageFlags pipe_stage_flags; | |
| VkPresentInfoKHR present; | |
| VkClearValue clear_values[2]; | |
| const VkDeviceSize offsets[1] = { 0 }; | |
| const VkCommandBuffer cmd_bufs[1] = { data.command_buffer }; | |
| VkSubmitInfo submit_info[1]; | |
| clear_values[0].color.float32[0] = 0.0f; | |
| clear_values[0].color.float32[1] = 0.0f; | |
| clear_values[0].color.float32[2] = 0.0f; | |
| clear_values[0].color.float32[3] = 0.0f; | |
| clear_values[1].depthStencil.depth = 1.0f; | |
| clear_values[1].depthStencil.stencil = 0; | |
| image_acquired_semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; | |
| image_acquired_semaphore_create_info.pNext = NULL; | |
| image_acquired_semaphore_create_info.flags = 0; | |
| ASSERT_VK(vkCreateSemaphore(data.device, & image_acquired_semaphore_create_info, NULL, & image_acquired_semaphore)); | |
| ASSERT_VK(vkAcquireNextImageKHR(data.device, data.swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &data.current_buffer)); | |
| rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; | |
| rp_begin.pNext = NULL; | |
| rp_begin.renderPass = data.render_pass; | |
| rp_begin.framebuffer = data.framebuffers[data.current_buffer]; | |
| rp_begin.renderArea.offset.x = 0; | |
| rp_begin.renderArea.offset.y = 0; | |
| rp_begin.renderArea.extent.width = data.width; | |
| rp_begin.renderArea.extent.height = data.height; | |
| rp_begin.clearValueCount = 2; | |
| rp_begin.pClearValues = clear_values; | |
| vkCmdBeginRenderPass(data.command_buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); | |
| vkCmdBindPipeline(data.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data.pipeline); | |
| vkCmdBindDescriptorSets(data.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, data.descriptor_set, 0, NULL); | |
| vkCmdBindVertexBuffers(data.command_buffer, 0, 1, &data.vertex.buf, offsets); | |
| data.viewport.height = (f32) data.height; | |
| data.viewport.width = (f32) data.width; | |
| data.viewport.minDepth = 0.0f; | |
| data.viewport.maxDepth = 1.0f; | |
| data.viewport.x = 0; | |
| data.viewport.y = 0; | |
| vkCmdSetViewport(data.command_buffer, 0, NUM_VIEWPORTS, &data.viewport); | |
| vkCmdDraw(data.command_buffer, 12 * 3, 1, 0, 0); | |
| vkCmdEndRenderPass(data.command_buffer); | |
| ASSERT_VK(vkEndCommandBuffer(data.command_buffer)); | |
| fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; | |
| fence_info.pNext = NULL; | |
| fence_info.flags = 0; | |
| vkCreateFence(data.device, &fence_info, NULL, &draw_fence); | |
| pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; | |
| submit_info[0].pNext = NULL; | |
| submit_info[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; | |
| submit_info[0].waitSemaphoreCount = 1; | |
| submit_info[0].pWaitSemaphores = &image_acquired_semaphore; | |
| submit_info[0].pWaitDstStageMask = &pipe_stage_flags; | |
| submit_info[0].commandBufferCount = 1; | |
| submit_info[0].pCommandBuffers = cmd_bufs; | |
| submit_info[0].signalSemaphoreCount = 0; | |
| submit_info[0].pSignalSemaphores = NULL; | |
| ASSERT_VK(vkQueueSubmit(data.graphics_queue, 1, submit_info, draw_fence)); | |
| present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; | |
| present.pNext = NULL; | |
| present.swapchainCount = 1; | |
| present.pSwapchains = &data.swapchain; | |
| present.pImageIndices = &data.current_buffer; | |
| present.pWaitSemaphores = NULL; | |
| present.waitSemaphoreCount = 0; | |
| present.pResults = NULL; | |
| { | |
| VkResult res; | |
| do { | |
| res = vkWaitForFences(data.device, 1, &draw_fence, VK_TRUE, FENCE_TIMEOUT); | |
| } while (res == VK_TIMEOUT); | |
| ASSERT_VK(res); | |
| } | |
| ASSERT_VK(vkQueuePresentKHR(data.present_queue, &present)); | |
| } // End of draw cube | |
| vkFreeCommandBuffers(data.device, data.cbp, 1, &data.command_buffer); | |
| vkDestroyCommandPool(data.device, data.cbp, NULL); | |
| vkDestroyDevice(data.device, NULL); | |
| vkDestroyInstance(data.instance, NULL); | |
| return(0); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment