diff options
| -rw-r--r-- | src/device.c | 244 | ||||
| -rw-r--r-- | src/device.h | 15 | ||||
| -rw-r--r-- | src/main.c | 7 | 
3 files changed, 249 insertions, 17 deletions
| diff --git a/src/device.c b/src/device.c index f85b1a6..23cece2 100644 --- a/src/device.c +++ b/src/device.c @@ -63,9 +63,13 @@ static int create_physical_device(device_t device, struct device_info *info);  static int create_logical_device(device_t device, struct device_info *info);  static int create_swap_chain(device_t device, struct device_info *info);  static int create_pipeline(device_t device, struct device_info *info); +static int create_command_pool(device_t device, struct device_info *info); +static int create_sync_objects(device_t device, struct device_info *info);  static void destroy_swap_chain(device_t device);  static void destroy_pipeline(device_t device); +// static void destroy_command_pool(device_t device); +static void destroy_sync_objects(device_t device);  // --- Helper Function ---  static char *str_VkResult(VkResult result); @@ -84,6 +88,11 @@ static int swap_chain_get_extent(VkSurfaceCapabilitiesKHR capabilities, VkExtent  #define PPLN device->pipeline  static int pipeline_load_shader_module(VkDevice device, char *path, VkShaderModule *module); +#define CMND device->command +static int command_buffer_record(device_t device, u32 image_index); + +#define SYNC device->sync +  F_LOAD_FILE_ALIGNED(u32) // from config.h  // --- Debug Functions --- @@ -125,6 +134,12 @@ device_t device_create(struct device_info *info)      PPLN.pipeline = VK_NULL_HANDLE;      PPLN.layout = VK_NULL_HANDLE;      PPLN.render_pass = VK_NULL_HANDLE; + +    CMND.pool = VK_NULL_HANDLE; + +    SYNC.semph_image_available = VK_NULL_HANDLE; +    SYNC.semph_render_finished = VK_NULL_HANDLE; +    SYNC.fence_inflight = VK_NULL_HANDLE;      CCHECK(create_instance);      CCHECK(create_surface); @@ -135,6 +150,8 @@ device_t device_create(struct device_info *info)      CCHECK(create_logical_device);      CCHECK(create_swap_chain);      CCHECK(create_pipeline); +    CCHECK(create_command_pool); +    CCHECK(create_sync_objects);      return device;      fail: @@ -146,6 +163,12 @@ void device_destroy(device_t device)  {      if(!device) return; +    vkDeviceWaitIdle(device->logical_device); + +    destroy_sync_objects(device); + +    vkDestroyCommandPool(device->logical_device, CMND.pool, NULL); +          destroy_pipeline(device);      destroy_swap_chain(device); @@ -161,6 +184,62 @@ void device_destroy(device_t device)      free(device);  } +int device_draw_frame(device_t device) +{ +    int ret = 1; + +    // wait for the previous frame to finish +    vkWaitForFences(device->logical_device, 1, &SYNC.fence_inflight, VK_TRUE, UINT64_MAX); +    vkResetFences(device->logical_device, 1, &SYNC.fence_inflight); + +    // aquire the next image the form the swap chain +    u32 image_index; +    vkAcquireNextImageKHR(device->logical_device, SWCH.swap_chain, UINT64_MAX, SYNC.semph_image_available, VK_NULL_HANDLE, &image_index); + +    // reset the command buffer +    vkResetCommandBuffer(CMND.buffer, 0); +    command_buffer_record(device, image_index); + +    // prepare the queue submit info +    VkSubmitInfo submit_info = {0}; +    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + +    VkSemaphore wait_semaphs[] = { SYNC.semph_image_available }; +    VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; +    submit_info.waitSemaphoreCount = ARR_SIZE(wait_semaphs); +    submit_info.pWaitSemaphores = wait_semaphs; +    submit_info.pWaitDstStageMask = wait_stages; + +    submit_info.commandBufferCount = 1; +    submit_info.pCommandBuffers = &CMND.buffer; + +    VkSemaphore signal_semphs[] = { SYNC.semph_image_available }; +    submit_info.signalSemaphoreCount = ARR_SIZE(signal_semphs); +    submit_info.pSignalSemaphores = signal_semphs; + +    // submit the graphics work +    VCHECK(vkQueueSubmit, device->graphics_queue, 1, &submit_info, SYNC.fence_inflight); + +    // prepare the graphics info +    VkPresentInfoKHR present_info = {0}; +    present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; +     +    present_info.waitSemaphoreCount = ARR_SIZE(signal_semphs); +    present_info.pWaitSemaphores = signal_semphs; + +    VkSwapchainKHR swap_chains[] = { SWCH.swap_chain }; +    present_info.swapchainCount = ARR_SIZE(swap_chains); +    present_info.pSwapchains = swap_chains; +    present_info.pImageIndices = &image_index; +    present_info.pResults = NULL; // Optional + +    vkQueuePresentKHR(device->present_queue, &present_info); +    +    ret = 0; +exit: +    return ret; +} +  static int create_instance(device_t device, struct device_info *info)  {      int ret = 1; @@ -177,8 +256,6 @@ static int create_instance(device_t device, struct device_info *info)      VkInstanceCreateInfo create_info = {0};      create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;      create_info.pApplicationInfo = &app_info; - -      create_info.enabledLayerCount = 0; @@ -503,18 +580,6 @@ static int create_pipeline(device_t device, struct device_info *info)      input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;      input_assembly.primitiveRestartEnable = VK_FALSE; -    // VkViewport viewport = {0}; -    // viewport.x = 0.0f; -    // viewport.y = 0.0f; -    // viewport.width = (float) SWCH.extent.width; -    // viewport.height = (float) SWCH.extent.height; -    // viewport.minDepth = 0.0f; -    // viewport.maxDepth = 1.0f; - -    // VkRect2D scissor = {0}; -    // scissor.offset = {0, 0}; -    // scissor.extent = SWCH.extent; -      VkPipelineViewportStateCreateInfo viewport_state = {0};      viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;      viewport_state.viewportCount = 1; @@ -594,12 +659,22 @@ static int create_pipeline(device_t device, struct device_info *info)      subpass.colorAttachmentCount = 1;      subpass.pColorAttachments = &color_attachment_ref; +    VkSubpassDependency dependency = {0}; +    dependency.srcSubpass = VK_SUBPASS_EXTERNAL; +    dependency.dstSubpass = 0; +    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; +    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; +    dependency.srcAccessMask = 0; +    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; +      VkRenderPassCreateInfo render_pass_info = {0};      render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;      render_pass_info.attachmentCount = 1;      render_pass_info.pAttachments = &color_attachment;      render_pass_info.subpassCount = 1;      render_pass_info.pSubpasses = &subpass; +    render_pass_info.dependencyCount = 1; +    render_pass_info.pDependencies = &dependency;      VCHECK(vkCreateRenderPass, device->logical_device, &render_pass_info, NULL, &PPLN.render_pass); @@ -626,7 +701,25 @@ static int create_pipeline(device_t device, struct device_info *info)      pipeline_info.basePipelineIndex = -1; // Optional      VCHECK(vkCreateGraphicsPipelines, device->logical_device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &PPLN.pipeline); -     + +    PPLN.framebuffers = xcalloc(SWCH.nimages, sizeof(*PPLN.framebuffers)); +    for(u32 i = 0; i < SWCH.nimages; i++) { +        VkImageView attachments[] = { +            SWCH.image_views[i] +        }; +         +        VkFramebufferCreateInfo framebuffer_info = {0}; +        framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; +        framebuffer_info.renderPass = PPLN.render_pass; +        framebuffer_info.attachmentCount = 1; +        framebuffer_info.pAttachments = attachments; +        framebuffer_info.width = SWCH.extent.width; +        framebuffer_info.height = SWCH.extent.height; +        framebuffer_info.layers = 1; +         +        VCHECK(vkCreateFramebuffer, device->logical_device, &framebuffer_info, NULL, &PPLN.framebuffers[i]); +    } +      ret = 0;  exit:      vkDestroyShaderModule(device->logical_device, frag_shader, NULL); @@ -636,11 +729,73 @@ exit:  static void destroy_pipeline(device_t device)  { +    for(u32 i = 0; i < SWCH.nimages; i++) { +        vkDestroyFramebuffer(device->logical_device, PPLN.framebuffers[i], NULL); +    } +    if(SWCH.nimages > 0) free(PPLN.framebuffers); +          vkDestroyPipeline(device->logical_device, PPLN.pipeline, NULL);      vkDestroyPipelineLayout(device->logical_device, PPLN.layout, NULL);      vkDestroyRenderPass(device->logical_device, PPLN.render_pass, NULL);  } +static int create_command_pool(device_t device, struct device_info *info) +{ +    (void)info; +    int ret = 1; + +    struct queue_family_idx indices; +    device_queue_families(device->physical_device, device->surface, &indices); +     +    VkCommandPoolCreateInfo pool_info = {0}; +    pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; +    pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; +    pool_info.queueFamilyIndex = indices.graphics_family; + +    VCHECK(vkCreateCommandPool, device->logical_device, &pool_info, NULL, &CMND.pool); + +    // allocate the command buffer(s) +    VkCommandBufferAllocateInfo allocate_info = {0}; +    allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; +    allocate_info.commandPool = CMND.pool; +    allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; +    allocate_info.commandBufferCount = 1; + +    VCHECK(vkAllocateCommandBuffers, device->logical_device, &allocate_info, &CMND.buffer); + +    ret = 0; +exit: +    return ret; +} + +static int create_sync_objects(device_t device, struct device_info *info) +{ +    (void)info; +    int ret = 1; + +    VkSemaphoreCreateInfo semph_info = {0}; +    semph_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; +     +    VkFenceCreateInfo fence_info = {0}; +    fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; +    fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; + +    VCHECK(vkCreateSemaphore, device->logical_device, &semph_info, NULL, &SYNC.semph_image_available); +    VCHECK(vkCreateSemaphore, device->logical_device, &semph_info, NULL, &SYNC.semph_render_finished); +    VCHECK(vkCreateFence, device->logical_device, &fence_info, NULL, &SYNC.fence_inflight); + +    ret = 0; +exit: +    return ret; +} + +static void destroy_sync_objects(device_t device) +{ +    vkDestroySemaphore(device->logical_device, SYNC.semph_image_available, NULL); +    vkDestroySemaphore(device->logical_device, SYNC.semph_render_finished, NULL); +    vkDestroyFence(device->logical_device, SYNC.fence_inflight, NULL); +} +  static int device_queue_families(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct queue_family_idx *queue_family)  {         u32 count = 0; @@ -800,6 +955,65 @@ exit:      return ret;  } +static int command_buffer_record(device_t device, u32 image_index) +{ +    int ret = 1; + +    // Begin the buffer +    VkCommandBufferBeginInfo begin_info = {0}; +    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; +    begin_info.flags = 0; // Optional +    begin_info.pInheritanceInfo = NULL; // Optional +     +    VCHECK(vkBeginCommandBuffer, CMND.buffer, &begin_info); + +    // Begin the render pass +    VkRenderPassBeginInfo render_pass_info = {0}; +    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; +    render_pass_info.renderPass = PPLN.render_pass; +    render_pass_info.framebuffer = PPLN.framebuffers[image_index]; + +    render_pass_info.renderArea.offset = (VkOffset2D){0, 0}; +    render_pass_info.renderArea.extent = SWCH.extent; + +    VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; +    render_pass_info.clearValueCount = 1; +    render_pass_info.pClearValues = &clear_color; + +    vkCmdBeginRenderPass(CMND.buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); + +    // Begin the drawing commands +    vkCmdBindPipeline(CMND.buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, PPLN.pipeline); + +    VkViewport viewport = {0}; +    viewport.x = 0.0f; +    viewport.y = 0.0f; +    viewport.width = (float)SWCH.extent.width; +    viewport.height = (float)SWCH.extent.height; +    viewport.minDepth = 0.0f; +    viewport.maxDepth = 1.0f; +     +    vkCmdSetViewport(CMND.buffer, 0, 1, &viewport); + +    VkRect2D scissor = {0}; +    scissor.offset = (VkOffset2D){0, 0}; +    scissor.extent = SWCH.extent; +    vkCmdSetScissor(CMND.buffer, 0, 1, &scissor); + +    // 3 vertices, 1 instance (for instanced rendering) +    // 0 is the first vertex, 0 is the fist instance +    vkCmdDraw(CMND.buffer, 3, 1, 0, 0); + +    // Cleaning up +    vkCmdEndRenderPass(CMND.buffer); + +    VCHECK(vkEndCommandBuffer, CMND.buffer); + +    ret = 0; +exit: +    return ret; +} +  #define X_VK_RESULT_TABLE(X)                   \      X(VK_SUCCESS)                              \      X(VK_NOT_READY)                            \ diff --git a/src/device.h b/src/device.h index 05bdbc1..fac15b9 100644 --- a/src/device.h +++ b/src/device.h @@ -38,10 +38,24 @@ typedef struct device {      struct pipeline {          VkRenderPass render_pass; +        VkFramebuffer *framebuffers; +                  VkPipelineLayout layout;          VkPipeline pipeline;      } pipeline; +    struct command { +        VkCommandPool pool; +        VkCommandBuffer buffer; +        // VkCommandBuffer *buffers; +    } command; + +    struct sync { +        VkSemaphore semph_image_available; +        VkSemaphore semph_render_finished; +        VkFence     fence_inflight; +    } sync; +  } * device_t;  struct device_info { @@ -56,5 +70,6 @@ struct device_info {  device_t device_create(struct device_info *info);  void device_destroy(device_t device); +int device_draw_frame(device_t device);  #endif @@ -6,6 +6,7 @@  #include "common.h"  // TODO: rename device.c/.h +//       to graphics.c/.h  window_t window;  device_t device; @@ -24,8 +25,8 @@ int main(void)      // populate window info      struct window_info win_info = {0};      win_info.title = "Test App"; -    win_info.w = 1200; -    win_info.h = 800; +    win_info.w = 640; +    win_info.h = 480;      // create window      window = window_create(&win_info); @@ -69,6 +70,8 @@ int main(void)                  running = 0;                  break;              } + +        device_draw_frame(device);      }      ret = 0; | 
