From: Eleni Maria Stea Date: Sat, 18 Sep 2021 11:04:11 +0000 (+0300) Subject: working swapchain X-Git-Url: https://eleni.mutantstargoat.com/git/?p=vkrt;a=commitdiff_plain;h=e123e37a567080a67a1d59837f52cada1b02c951 working swapchain +a hundred other fixes and changes --- diff --git a/src/main.c b/src/main.c index 6309b41..eb1cf18 100644 --- a/src/main.c +++ b/src/main.c @@ -20,31 +20,34 @@ clb_reshape(GLFWwindow *win, int width, int height); /* static functions */ static bool -init(); +init(void); static void -cleanup(); +cleanup(void); static void -display(); - +display(void); /* static variables */ static GLFWwindow *win; +static bool redraw_pending; + +static bool vk_enable_layers; static int win_w = 800; static int win_h = 600; static struct vk_ctx vk_core; static VkSurfaceKHR vk_surf; -static int vsz, fsz; static struct vk_renderer vk_rnd; static struct vk_swapchain vk_chain; static struct vk_semaphores vk_sema; -static struct vk_image_attachment vk_color_att; -static struct vk_image_attachment vk_depth_att; -static struct vk_image_props vk_depth_att_props; +static struct vk_attachment vk_depth_att; +static float vk_fb_color[4] = { 0.0, 0.0, 0.5, 1.0 }; + +/* make array later if many cmd buffers */ +static VkCommandBuffer vk_cmd_buf; /* empty for as long as we hardcode the vertices in the vertex shader */ static struct vk_vertex_info vk_vert_info; @@ -63,10 +66,14 @@ int main(int argc, char** argv) clb_reshape(win, win_w, win_h); /* event loop */ + redraw_pending = true; while(!glfwWindowShouldClose(win)) { - display(); - glfwPollEvents(); + glfwWaitEvents(); + if (redraw_pending) { + redraw_pending = false; + display(); + } } return 0; @@ -75,9 +82,11 @@ int main(int argc, char** argv) /* static functions */ static bool -init() +init(void) { - char *vsdr, *fsdr; + char *vsdr = 0; + char *fsdr = 0; + int vsz, fsz; /* initialize GLFW */ @@ -101,9 +110,11 @@ init() return false; } + glfwSetKeyCallback(win, clb_key); + /* initialize Vulkan context (instance) */ - if (!vk_init_ctx_for_rendering(&vk_core)) { + if (!vk_init_ctx_for_rendering(&vk_core, true, vk_enable_layers)) { fprintf(stderr, "Failed to initialize Vulkan context.\n"); return false; } @@ -114,16 +125,25 @@ init() if (glfwCreateWindowSurface(vk_core.inst, win, 0, &vk_surf) != VK_SUCCESS) { fprintf(stderr, "Failed to create XCB surface.\n"); - glfwTerminate(); - return false; } /* create semaphores */ - vk_create_semaphores(&vk_core, false, &vk_sema); + if (!vk_create_semaphores(&vk_core, false, &vk_sema)) { + fprintf(stderr, "No semaphores were created.\n"); + goto fail; + } /* create swapchain */ - vk_create_swapchain(&vk_core, win_w, win_h, false, vk_surf, VK_NULL_HANDLE, &vk_chain); + if (!vk_create_swapchain(&vk_core, win_w, win_h, false, vk_surf, 0, &vk_chain)) { + fprintf(stderr, "No swapchain was created.\n"); + goto fail; + } + + if (vk_chain.swapchain == VK_NULL_HANDLE) { + fprintf(stderr, "Invalid swapchain handle.\n"); + goto fail; + } /* create shaders */ vsdr = sdr_load("data/main.vert.spv", &vsz); @@ -138,27 +158,48 @@ init() VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - false, &vk_depth_att_props)) { + false, true, false, + &vk_depth_att.props)) { fprintf(stderr, "Unsupported depth image properties\n"); return false; } - if (!vk_create_image(&vk_core, &vk_depth_att_props, &vk_depth_att.obj)) { + if (!vk_create_image(&vk_core, &vk_depth_att.props, &vk_depth_att.obj)) { fprintf(stderr, "Failed to create depth attachment.\n"); - return false; + goto fail; } /* create renderer */ - if (!vk_create_renderer(&vk_core, vsdr, vsz, fsdr, fsz, - false, false, 0, &vk_depth_att, + if (!vk_create_renderer(&vk_core, + vsdr, vsz, fsdr, fsz, + win_w, win_h, 1, + false, false, + vk_chain.num_atts, vk_chain.atts, &vk_depth_att, &vk_vert_info, &vk_rnd)) { - fprintf(stderr, "Failed to create renderer.\n"); - return false; + goto fail; + } + + /* create cmd buffer */ + if ((vk_cmd_buf = vk_create_cmd_buffer(&vk_core)) == VK_NULL_HANDLE) { + fprintf(stderr, "Failed to create command buffer.\n"); + goto fail; + } + + /* record cmd buffer */ + if (!vk_record_cmd_buffer(&vk_core, vk_cmd_buf, + &vk_rnd, 0, + 4, vk_fb_color, + vk_chain.num_atts + 1, 0, + 0, 0, win_w, win_h)) { + fprintf(stderr, "Failed to record command buffer.\n"); + goto fail; } + free(vsdr); + free(fsdr); + /* set GLFW callbacks */ - glfwSetKeyCallback(win, clb_key); - glfwSetWindowSizeCallback(win, clb_reshape); + /* glfwSetWindowSizeCallback(win, clb_reshape); */ /* glfwSetCursorPosCallback(win, clb_motion); @@ -166,19 +207,75 @@ init() */ return true; + +fail: + free(vsdr); + free(fsdr); + + return false; } static void -display() +display(void) { + uint32_t img_idx; + VkSubmitInfo sinfo; + VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkPresentInfoKHR pinfo; + + vkAcquireNextImageKHR(vk_core.dev, vk_chain.swapchain, + UINT64_MAX, vk_sema.frame_ready, 0, &img_idx); + + memset(&sinfo, 0, sizeof sinfo); + sinfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + sinfo.waitSemaphoreCount = 1; + sinfo.pWaitSemaphores = &vk_sema.frame_ready; + sinfo.pWaitDstStageMask = &wait_stages; + sinfo.commandBufferCount = 1; + sinfo.pCommandBuffers = &vk_cmd_buf; + sinfo.signalSemaphoreCount = 1; + sinfo.pSignalSemaphores = &vk_sema.frame_done; + + if (vkQueueSubmit(vk_core.queue, 1, &sinfo, 0) != 0) { + fprintf(stderr, "Failed to submit draw commands.\n"); + abort(); + } + + memset(&pinfo, 0, sizeof pinfo); + pinfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + pinfo.waitSemaphoreCount = 1; + pinfo.pWaitSemaphores = &vk_sema.frame_done; + pinfo.swapchainCount = 1; + pinfo.pSwapchains = &vk_chain.swapchain; + pinfo.pImageIndices = &img_idx; + + vkQueuePresentKHR(vk_core.queue, &pinfo); } static void -cleanup() +cleanup(void) { + vkQueueWaitIdle(vk_core.queue); + + if (vk_cmd_buf != VK_NULL_HANDLE) { + vkResetCommandBuffer(vk_cmd_buf, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + } + + vk_destroy_image(&vk_core, &vk_depth_att.obj); vk_destroy_renderer(&vk_core, &vk_rnd); + vk_destroy_semaphores(&vk_core, &vk_sema); + + if (vk_chain.swapchain) { + vk_destroy_swapchain(&vk_core, &vk_chain); + vkDestroySurfaceKHR(vk_core.inst, vk_surf, 0); + } + + glfwDestroyWindow(win); - vk_cleanup_ctx(&vk_core); + if (!vk_enable_layers) + vkFreeCommandBuffers(vk_core.dev, vk_core.cmd_pool, 1, &vk_cmd_buf); + + vk_cleanup_ctx(&vk_core, vk_enable_layers); glfwTerminate(); } @@ -201,8 +298,4 @@ clb_key(GLFWwindow *win, int key, int scancode, static void clb_reshape(GLFWwindow *win, int width, int height) { - /* set viewport */ - - win_w = width; - win_h = height; } diff --git a/src/vk.c b/src/vk.c index b4e9eb7..9e80dd3 100644 --- a/src/vk.c +++ b/src/vk.c @@ -9,7 +9,18 @@ static VkViewport viewport; static VkRect2D scissor; -static bool enable_layers = true; +static VkPipelineCache pipeline_cache; + +/* when I extend the program to use more than one buffers + * I might need to store them in this list and access it + * using multiple threads + * + * man realloc + */ +#if 0 +static VkCommandBuffer *command_buffers; +static uint32_t num_command_buffers; +#endif /* static functions */ @@ -251,80 +262,105 @@ create_cmd_pool(struct vk_ctx *ctx) { VkCommandPoolCreateInfo cmd_pool_info; VkCommandPool cmd_pool; - VkDevice dev = ctx->dev; memset(&cmd_pool_info, 0, sizeof cmd_pool_info); cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; cmd_pool_info.queueFamilyIndex = ctx->qfam_idx; cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS) + if (vkCreateCommandPool(ctx->dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS) return 0; return cmd_pool; } -static VkRenderPass -create_renderpass(struct vk_ctx *ctx, - struct vk_image_props *color_img_props, - struct vk_image_props *depth_img_props) +static VkPipelineCache +create_pipeline_cache(struct vk_ctx *ctx) { - uint32_t num_attachments = 2; - VkAttachmentDescription att_dsc[2]; - VkAttachmentReference att_rfc[2]; - VkSubpassDescription subpass_dsc[1]; - VkRenderPassCreateInfo rpass_info; + VkPipelineCacheCreateInfo pc_info; + VkPipelineCache pcache; - /* VkAttachmentDescription */ - memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]); + memset(&pc_info, 0, sizeof pc_info); + pc_info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; - att_dsc[0].samples = get_num_samples(color_img_props->num_samples); - att_dsc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - att_dsc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - att_dsc[0].initialLayout = color_img_props->in_layout; - att_dsc[0].finalLayout = color_img_props->end_layout; - att_dsc[0].format = color_img_props->format; - att_dsc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - att_dsc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - - att_dsc[1].samples = get_num_samples(depth_img_props->num_samples); - - /* We might want to reuse a depth buffer */ - if (depth_img_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED) { - att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - } - else { - att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + if (vkCreatePipelineCache(ctx->dev, &pc_info, 0, &pcache) != VK_SUCCESS) { + fprintf(stderr, "Failed to create a pipeline cache.\n"); + return VK_NULL_HANDLE; } - att_dsc[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - att_dsc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - att_dsc[1].initialLayout = depth_img_props->in_layout; - att_dsc[1].finalLayout = depth_img_props->end_layout; - att_dsc[1].format = depth_img_props->format; + return pcache; +} - /* VkAttachmentReference */ - memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]); +static VkRenderPass +create_renderpass(struct vk_ctx *ctx, + uint32_t num_color_atts, + struct vk_attachment *color_atts, + struct vk_attachment *depth_att) +{ + VkAttachmentDescription *att_dsc; + VkAttachmentReference *att_rfc; - att_rfc[0].layout = color_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL; - att_rfc[0].attachment = 0; + /* one subpass for the moment: */ + VkSubpassDescription subpass_dsc[1]; + VkRenderPassCreateInfo rpass_info; - att_rfc[1].layout = depth_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL; - att_rfc[1].attachment = 1; + int i; + uint32_t num_atts = num_color_atts + 1; + bool has_layout = depth_att->props.in_layout != + VK_IMAGE_LAYOUT_UNDEFINED; + + att_dsc = malloc(num_atts * sizeof att_dsc[0]); + att_rfc = malloc(num_atts * sizeof att_rfc[0]); + + memset(att_dsc, 0, num_atts * sizeof att_dsc[0]); + memset(att_rfc, 0, num_atts * sizeof att_rfc[0]); + + /* color attachments description (we can have many) */ + for (i = 0; i < num_color_atts; i++) { + att_dsc[i].samples = get_num_samples(color_atts[i].props.num_samples); + att_dsc[i].initialLayout = color_atts[i].props.in_layout; + att_dsc[i].finalLayout = color_atts[i].props.end_layout; + att_dsc[i].format = color_atts[i].props.format; + + att_dsc[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + att_dsc[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + att_dsc[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + att_dsc[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + + att_rfc[i].attachment = i; + att_rfc[i].layout = color_atts[i].props.tiling != VK_IMAGE_TILING_OPTIMAL ? + VK_IMAGE_LAYOUT_GENERAL : + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + } + + /* depth attachment description (we can have only one) */ + att_dsc[num_color_atts].samples = get_num_samples(depth_att->props.num_samples); + att_dsc[num_color_atts].initialLayout = depth_att->props.in_layout; + att_dsc[num_color_atts].finalLayout = depth_att->props.end_layout; + att_dsc[num_color_atts].format = depth_att->props.format; + /* we might want to reuse the depth buffer when it's filled */ + att_dsc[num_color_atts].loadOp = has_layout ? + VK_ATTACHMENT_LOAD_OP_LOAD : + VK_ATTACHMENT_LOAD_OP_CLEAR; + att_dsc[num_color_atts].stencilLoadOp = has_layout ? + VK_ATTACHMENT_LOAD_OP_LOAD : + VK_ATTACHMENT_LOAD_OP_CLEAR; + att_dsc[num_color_atts].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + att_rfc[num_color_atts].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + att_rfc[num_color_atts].attachment = num_color_atts; /* VkSubpassDescription */ memset(&subpass_dsc, 0, sizeof subpass_dsc); subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass_dsc[0].colorAttachmentCount = 1; + subpass_dsc[0].colorAttachmentCount = num_color_atts; subpass_dsc[0].pColorAttachments = &att_rfc[0]; - subpass_dsc[0].pDepthStencilAttachment = &att_rfc[1]; + subpass_dsc[0].pDepthStencilAttachment = &att_rfc[num_color_atts]; /* VkRenderPassCreateInfo */ memset(&rpass_info, 0, sizeof rpass_info); rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rpass_info.attachmentCount = num_attachments; + rpass_info.attachmentCount = num_atts; rpass_info.pAttachments = att_dsc; rpass_info.subpassCount = 1; rpass_info.pSubpasses = subpass_dsc; @@ -335,6 +371,9 @@ create_renderpass(struct vk_ctx *ctx, rpass = VK_NULL_HANDLE; } + free(att_dsc); + free(att_rfc); + return rpass; } @@ -350,8 +389,9 @@ get_image_type(uint32_t h, uint32_t d) return VK_IMAGE_TYPE_2D; } +#if 0 static VkImageViewType -get_image_view_type(struct vk_image_props *props) +get_image_view_type(struct vk_att_props *props) { VkImageType type = get_image_type(props->h, props->depth); switch(type) { @@ -381,6 +421,7 @@ get_image_view_type(struct vk_image_props *props) return VK_IMAGE_VIEW_TYPE_2D; } } +#endif static VkImageAspectFlagBits get_aspect_from_depth_format(VkFormat depth_format) @@ -464,91 +505,82 @@ create_image_view(struct vk_ctx *ctx, return true; } -static void -create_framebuffer(struct vk_ctx *ctx, - struct vk_image_attachment *color_att, - struct vk_image_attachment *depth_att, - struct vk_renderer *renderer) +static bool +create_attachment_views(struct vk_ctx *ctx, int num_color_att, + struct vk_attachment *color_att, + struct vk_attachment *depth_att) { VkImageSubresourceRange sr; - VkFramebufferCreateInfo fb_info; - VkImageView atts[2]; - VkImageViewType view_type = get_image_view_type(&color_att->props); - - if (!color_att->obj.img || !depth_att->obj.img) { - fprintf(stderr, "Invalid framebuffer attachment image.\n"); - goto fail; - } - - /* create image views */ + int i; - /* VKImageSubresourceRange */ + /* depth attachments */ memset(&sr, 0, sizeof sr); - sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - /* If an application wants to use all mip levels - * or layers in an image after the baseMipLevel - * or baseArrayLayer, it can set levelCount and - * layerCount to the special values - * VK_REMAINING_MIP_LEVELS and - * VK_REMAINING_ARRAY_LAYERS without knowing the - * exact number of mip levels or layers. - */ + sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format); sr.baseMipLevel = 0; - sr.levelCount = color_att->props.num_levels; + sr.levelCount = 1; sr.baseArrayLayer = 0; - sr.layerCount = color_att->props.num_layers; + sr.layerCount = 1; - /* color view */ - if (!color_att->obj.img_view) { - if (!create_image_view(ctx, color_att->obj.img, view_type, color_att->props.format, sr, false, &color_att->obj.img_view)) { - fprintf(stderr, "Failed to create color image view for framebuffer.\n"); - vk_destroy_image(ctx, &color_att->obj); - goto fail; - } - } + create_image_view(ctx, depth_att->obj.img, VK_IMAGE_VIEW_TYPE_2D, + depth_att->props.format, sr, false, + &depth_att->obj.img_view); - /* depth view */ memset(&sr, 0, sizeof sr); - sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format); - sr.baseMipLevel = 0; - sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1; - sr.baseArrayLayer = 0; - sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1; + sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - if (!depth_att->obj.img_view) { - if (!create_image_view(ctx, depth_att->obj.img, - depth_att->props.num_layers > 1 ? - VK_IMAGE_VIEW_TYPE_2D_ARRAY : - VK_IMAGE_VIEW_TYPE_2D, - depth_att->props.format, - sr, - false, - &depth_att->obj.img_view)) { - fprintf(stderr, "Failed to create depth image view for framebuffer.\n"); - vk_destroy_image(ctx, &depth_att->obj); - goto fail; - } + for (i = 0; i < num_color_att; i++) { + /* FIXME: in case of mipmaps */ + sr.baseMipLevel = 0; + sr.levelCount = color_att[i].props.num_levels; + sr.baseArrayLayer = 0; + sr.layerCount = color_att[i].props.num_layers; + + create_image_view(ctx, color_att[i].obj.img, VK_IMAGE_VIEW_TYPE_2D, + color_att[i].props.format, sr, color_att[i].props.is_swapchain, + &color_att[i].obj.img_view); } - atts[0] = color_att->obj.img_view; - atts[1] = depth_att->obj.img_view; + return true; +} + +static void +create_framebuffer(struct vk_ctx *ctx, + int width, int height, + int num_color_atts, + struct vk_attachment *color_att, + struct vk_attachment *depth_att, + struct vk_renderer *renderer) +{ + VkFramebufferCreateInfo fb_info; + VkImageView *atts; + int i; + int num_atts = num_color_atts + 1; + + atts = malloc(num_atts * sizeof atts[0]); + + for (i = 0; i < num_color_atts; i++) { + atts[i] = color_att[i].obj.img_view; + } + atts[num_color_atts] = depth_att->obj.img_view; memset(&fb_info, 0, sizeof fb_info); fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; fb_info.renderPass = renderer->renderpass; - fb_info.width = color_att->props.w; - fb_info.height = color_att->props.h; - fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1; - fb_info.attachmentCount = 2; + fb_info.width = width; + fb_info.height = height; + fb_info.layers = 1; + fb_info.attachmentCount = num_atts; fb_info.pAttachments = atts; if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS) goto fail; + free(atts); return; fail: fprintf(stderr, "Failed to create framebuffer.\n"); + free(atts); renderer->fb = VK_NULL_HANDLE; } @@ -574,19 +606,20 @@ create_shader_module(struct vk_ctx *ctx, return sm; } -static void -create_pipeline(struct vk_ctx *ctx, - uint32_t width, - uint32_t height, - uint32_t num_samples, - bool enable_depth, - bool enable_stencil, - struct vk_renderer *renderer) +static bool +create_graphics_pipeline(struct vk_ctx *ctx, + uint32_t width, + uint32_t height, + uint32_t num_samples, + uint32_t num_color_atts, + bool enable_depth, + bool enable_stencil, + struct vk_renderer *renderer) { VkVertexInputBindingDescription vert_bind_dsc[1]; VkVertexInputAttributeDescription vert_att_dsc[1]; - VkPipelineColorBlendAttachmentState cb_att_state[1]; + VkPipelineColorBlendAttachmentState *cb_att_state; VkPipelineVertexInputStateCreateInfo vert_input_info; VkPipelineInputAssemblyStateCreateInfo asm_info; VkPipelineViewportStateCreateInfo viewport_info; @@ -681,7 +714,7 @@ create_pipeline(struct vk_ctx *ctx, /* VkPipelineMultisampleStateCreateInfo */ memset(&ms_info, 0, sizeof ms_info); ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - ms_info.rasterizationSamples = num_samples; + ms_info.rasterizationSamples = get_num_samples(num_samples); /* VkStencilOpState */ /* The default values for ES are taken by Topi Pohjolainen's code */ @@ -727,16 +760,23 @@ create_pipeline(struct vk_ctx *ctx, ds_info.front = ds_info.back; /* VkPipelineColorBlendAttachmentState */ - memset(&cb_att_state[0], 0, sizeof cb_att_state[0]); - cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | - VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | - VK_COLOR_COMPONENT_A_BIT); + cb_att_state = malloc(num_color_atts * sizeof cb_att_state[0]); + if (!cb_att_state) { + fprintf(stderr, "Failed to allocate color blend attachment state for each attachment.\n"); + goto fail; + } + memset(cb_att_state, 0, num_color_atts * sizeof cb_att_state[0]); + for (i = 0; i < num_color_atts; i++) { + cb_att_state[i].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT); + } /* VkPipelineColorBlendStateCreateInfo */ memset(&cb_info, 0, sizeof cb_info); cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - cb_info.attachmentCount = 1; + cb_info.attachmentCount = num_color_atts; cb_info.pAttachments = cb_att_state; /* default in ES 3.1 */ for (i = 0; i < 4; i++) { @@ -770,7 +810,7 @@ create_pipeline(struct vk_ctx *ctx, if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) { fprintf(stderr, "Failed to create pipeline layout\n"); renderer->pipeline = VK_NULL_HANDLE; - return; + goto fail; } renderer->pipeline_layout = pipeline_layout; @@ -795,25 +835,15 @@ create_pipeline(struct vk_ctx *ctx, &renderer->pipeline) != VK_SUCCESS) { fprintf(stderr, "Failed to create graphics pipeline.\n"); renderer->pipeline = VK_NULL_HANDLE; + goto fail; } -} -static VkCommandBuffer -create_cmd_buf(VkDevice dev, VkCommandPool cmd_pool) -{ - VkCommandBuffer cmd_buf; - VkCommandBufferAllocateInfo alloc_info; - - memset(&alloc_info, 0, sizeof alloc_info); - alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - alloc_info.commandBufferCount = 1; - alloc_info.commandPool = cmd_pool; - - if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS) - return 0; + free(cb_att_state); + return true; - return cmd_buf; +fail: + free(cb_att_state); + return false; } static uint32_t @@ -933,7 +963,7 @@ alloc_image_memory(struct vk_ctx *ctx, bool is_external, struct vk_image_obj *im } static bool -are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props) +are_props_supported(struct vk_ctx *ctx, struct vk_att_props *props) { VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info; VkExternalImageFormatProperties ext_img_fmt_props; @@ -941,6 +971,7 @@ are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props) int i; VkPhysicalDeviceImageFormatInfo2 img_fmt_info; VkImageFormatProperties2 img_fmt_props; + VkImageUsageFlagBits all_flags[] = { VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT, @@ -962,28 +993,30 @@ are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props) }; VkImageUsageFlagBits flags = 0; - VkExternalMemoryFeatureFlagBits export_feature_flags = - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT; - VkExternalMemoryHandleTypeFlagBits handle_type = - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + VkExternalMemoryFeatureFlagBits export_feature_flags = props->need_export ? + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT : 0; + VkExternalMemoryHandleTypeFlagBits handle_type = props->need_export ? + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR : 0; - memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info); - ext_img_fmt_info.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; - ext_img_fmt_info.handleType = handle_type; + if (props->need_export) { + memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info); + ext_img_fmt_info.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; + ext_img_fmt_info.handleType = handle_type; - memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props); - ext_img_fmt_props.sType = - VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES; + memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props); + ext_img_fmt_props.sType = + VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES; + } memset(&img_fmt_props, 0, sizeof img_fmt_props); img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; - img_fmt_props.pNext = &ext_img_fmt_props; + img_fmt_props.pNext = props->need_export ? &ext_img_fmt_props : 0; memset(&img_fmt_info, 0, sizeof img_fmt_info); img_fmt_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; - img_fmt_info.pNext = &ext_img_fmt_info; + img_fmt_info.pNext = props->need_export ? &ext_img_fmt_info : 0; img_fmt_info.format = props->format; img_fmt_info.type = get_image_type(props->h, props->depth); img_fmt_info.tiling = props->tiling; @@ -991,8 +1024,8 @@ are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props) for (i = 0; i < ARRAY_SIZE(all_flags); i++) { img_fmt_info.usage = all_flags[i]; if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev, - &img_fmt_info, - &img_fmt_props) == VK_SUCCESS) { + &img_fmt_info, + &img_fmt_props) == VK_SUCCESS) { flags |= all_flags[i]; } } @@ -1002,8 +1035,11 @@ are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props) img_fmt_info.usage = flags; } else { - fprintf(stderr, "Unsupported Vulkan format properties: usage.\n"); - return false; + if (!props->is_swapchain) { + fprintf(stderr, "Unsupported Vulkan format properties: usage.\n"); + return false; + } + img_fmt_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; } if (vkGetPhysicalDeviceImageFormatProperties2 @@ -1137,7 +1173,8 @@ success: /* exposed Vulkan functions */ bool -vk_init_ctx(struct vk_ctx *ctx) +vk_init_ctx(struct vk_ctx *ctx, + bool enable_layers) { if ((ctx->inst = create_instance(enable_layers)) == VK_NULL_HANDLE) { fprintf(stderr, "Failed to create Vulkan instance.\n"); @@ -1158,14 +1195,16 @@ vk_init_ctx(struct vk_ctx *ctx) return true; fail: - vk_cleanup_ctx(ctx); + vk_cleanup_ctx(ctx, enable_layers); return false; } bool -vk_init_ctx_for_rendering(struct vk_ctx *ctx) +vk_init_ctx_for_rendering(struct vk_ctx *ctx, + bool enable_cache, + bool enable_layers) { - if (!vk_init_ctx(ctx)) { + if (!vk_init_ctx(ctx, enable_layers)) { fprintf(stderr, "Failed to initialize Vulkan.\n"); return false; } @@ -1175,37 +1214,45 @@ vk_init_ctx_for_rendering(struct vk_ctx *ctx) goto fail; } - if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) == - VK_NULL_HANDLE) { - fprintf(stderr, "Failed to create command buffer.\n"); - goto fail; - } - vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue); if (!ctx->queue) { fprintf(stderr, "Failed to get command queue.\n"); goto fail; } + if (enable_cache) { + if (!(pipeline_cache = create_pipeline_cache(ctx))) { + fprintf(stderr, "Failed to create pipeline cache.\n"); + goto fail; + } + } + return true; fail: - vk_cleanup_ctx(ctx); + vk_cleanup_ctx(ctx, enable_layers); return false; } void -vk_cleanup_ctx(struct vk_ctx *ctx) +vk_destroy_cmd_bufs(struct vk_ctx *ctx, + uint32_t num_buffers, + VkCommandBuffer *buffers) { - if (enable_layers) { - return; + int i; + for (i = 0; i < num_buffers; i++) { + vkResetCommandBuffer(buffers[i], + VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); } + vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, num_buffers, &buffers[i]); +} - if (ctx->cmd_buf != VK_NULL_HANDLE) { - vkResetCommandBuffer(ctx->cmd_buf, - VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); - vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf); - ctx->cmd_buf = VK_NULL_HANDLE; +void +vk_cleanup_ctx(struct vk_ctx *ctx, + bool enable_layers) +{ + if (enable_layers) { + return; } if (ctx->cmd_pool != VK_NULL_HANDLE) { @@ -1215,6 +1262,11 @@ vk_cleanup_ctx(struct vk_ctx *ctx) ctx->cmd_pool = VK_NULL_HANDLE; } + if (pipeline_cache != VK_NULL_HANDLE) { + vkDestroyPipelineCache(ctx->dev, pipeline_cache, 0); + pipeline_cache = VK_NULL_HANDLE; + } + if (ctx->dev != VK_NULL_HANDLE) { vkDestroyDevice(ctx->dev, 0); ctx->dev = VK_NULL_HANDLE; @@ -1228,7 +1280,7 @@ vk_cleanup_ctx(struct vk_ctx *ctx) bool vk_create_image(struct vk_ctx *ctx, - struct vk_image_props *props, + struct vk_att_props *props, struct vk_image_obj *img) { VkImageCreateInfo img_info; @@ -1283,7 +1335,7 @@ vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj) bool vk_create_ext_image(struct vk_ctx *ctx, - struct vk_image_props *props, struct vk_image_obj *img) + struct vk_att_props *props, struct vk_image_obj *img) { VkExternalMemoryImageCreateInfo ext_img_info; VkImageCreateInfo img_info; @@ -1342,8 +1394,10 @@ vk_fill_image_props(struct vk_ctx *ctx, VkImageTiling tiling, VkImageLayout in_layout, VkImageLayout end_layout, + bool is_swapchain, + bool is_depth, bool need_export, - struct vk_image_props *props) + struct vk_att_props *props) { props->w = w; props->h = h; @@ -1358,6 +1412,9 @@ vk_fill_image_props(struct vk_ctx *ctx, props->in_layout = in_layout; props->end_layout = end_layout; + + props->is_swapchain = is_swapchain; + props->is_depth = is_depth; props->need_export = need_export; if (!are_props_supported(ctx, props)) @@ -1372,10 +1429,13 @@ vk_create_renderer(struct vk_ctx *ctx, unsigned int vs_size, const char *fs_src, unsigned int fs_size, + int w, int h, + uint32_t num_samples, bool enable_depth, bool enable_stencil, - struct vk_image_attachment *color_att, - struct vk_image_attachment *depth_att, + int num_color_att, + struct vk_attachment *color_att, + struct vk_attachment *depth_att, struct vk_vertex_info *vert_info, struct vk_renderer *renderer) { @@ -1383,17 +1443,22 @@ vk_create_renderer(struct vk_ctx *ctx, if (vert_info) renderer->vertex_info = *vert_info; - if (!color_att || depth_att) { - fprintf(stderr, "Empty attachment.\n"); + /* create image views for each attachment */ + if (!create_attachment_views(ctx, num_color_att, color_att, depth_att)) goto fail; - } - renderer->renderpass = create_renderpass(ctx, &color_att->props, - &depth_att->props); + renderer->renderpass = create_renderpass(ctx, + num_color_att, + color_att, + depth_att); + if (renderer->renderpass == VK_NULL_HANDLE) goto fail; - create_framebuffer(ctx, color_att, depth_att, renderer); + create_framebuffer(ctx, + w, h, + num_color_att, color_att, + depth_att, renderer); if (renderer->fb == VK_NULL_HANDLE) goto fail; @@ -1405,9 +1470,13 @@ vk_create_renderer(struct vk_ctx *ctx, if (renderer->fs == VK_NULL_HANDLE) goto fail; - create_pipeline(ctx, color_att->props.w, color_att->props.h, - color_att->props.num_samples, enable_depth, - enable_stencil, renderer); + /* FIXME this is only for graphics atm */ + if(!create_graphics_pipeline(ctx, w, h, + num_samples, + num_color_att, + enable_depth, + enable_stencil, renderer)) + goto fail; if (renderer->pipeline == VK_NULL_HANDLE) goto fail; @@ -1415,7 +1484,7 @@ vk_create_renderer(struct vk_ctx *ctx, return true; fail: - fprintf(stderr, "Failed to create graphics pipeline.\n"); + fprintf(stderr, "Failed to create renderer.\n"); vk_destroy_renderer(ctx, renderer); return false; } @@ -1570,29 +1639,55 @@ vk_destroy_buffer(struct vk_ctx *ctx, bo->mobj.mem = VK_NULL_HANDLE; } -void -vk_draw(struct vk_ctx *ctx, - struct vk_buf *vbo, - struct vk_renderer *renderer, - float *vk_fb_color, - uint32_t vk_fb_color_count, - struct vk_semaphores *semaphores, - struct vk_image_attachment *attachments, - uint32_t n_attachments, - float x, float y, - float w, float h) +VkCommandBuffer +vk_create_cmd_buffer(struct vk_ctx *ctx) +{ + VkCommandBuffer cmd_buf; + VkCommandBufferAllocateInfo alloc_info; + + memset(&alloc_info, 0, sizeof alloc_info); + alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + alloc_info.commandBufferCount = 1; + alloc_info.commandPool = ctx->cmd_pool; + + if (vkAllocateCommandBuffers(ctx->dev, &alloc_info, &cmd_buf) != VK_SUCCESS) + return 0; + + return cmd_buf; +} + +bool +vk_record_cmd_buffer(struct vk_ctx *ctx, + VkCommandBuffer cmd_buf, + struct vk_renderer *renderer, + struct vk_buf *vbo, + uint32_t vk_fb_color_count, + float *vk_fb_color, + uint32_t num_atts, + struct vk_attachment *atts, + float x, float y, + float w, float h) { VkCommandBufferBeginInfo cmd_begin_info; VkRenderPassBeginInfo rp_begin_info; VkRect2D rp_area; - VkClearValue clear_values[2]; - VkSubmitInfo submit_info; + VkClearValue *clear_values; int i; VkDeviceSize offsets[] = {0}; - VkPipelineStageFlagBits stage_flags; + int num_vertices; struct vk_dims img_size; assert(vk_fb_color_count == 4); + /* if cmd_buf is null create it */ + if (!cmd_buf) { + if ((cmd_buf = vk_create_cmd_buffer(ctx)) == + VK_NULL_HANDLE) { + fprintf(stderr, "Failed to create command buffer.\n"); + return false; + } + } + /* VkCommandBufferBeginInfo */ memset(&cmd_begin_info, 0, sizeof cmd_begin_info); cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -1606,15 +1701,17 @@ vk_draw(struct vk_ctx *ctx, rp_area.offset.y = y; /* VkClearValue */ - memset(&clear_values[0], 0, sizeof clear_values[0]); - clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */ - clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */ - clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */ - clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */ + clear_values = malloc(num_atts * sizeof clear_values[0]); + memset(clear_values, 0, num_atts * sizeof clear_values[0]); - memset(&clear_values[1], 0, sizeof clear_values[1]); - clear_values[1].depthStencil.depth = 1.0; - clear_values[1].depthStencil.stencil = 0; + for (i = 0; i < num_atts - 1; i++) { + clear_values[i].color.float32[0] = vk_fb_color[0]; + clear_values[i].color.float32[1] = vk_fb_color[1]; + clear_values[i].color.float32[2] = vk_fb_color[2]; + clear_values[i].color.float32[3] = vk_fb_color[3]; + } + clear_values[num_atts - 1].depthStencil.depth = 1.0f; + clear_values[num_atts - 1].depthStencil.stencil = 0; /* VkRenderPassBeginInfo */ memset(&rp_begin_info, 0, sizeof rp_begin_info); @@ -1622,32 +1719,11 @@ vk_draw(struct vk_ctx *ctx, rp_begin_info.renderPass = renderer->renderpass; rp_begin_info.framebuffer = renderer->fb; rp_begin_info.renderArea = rp_area; - rp_begin_info.clearValueCount = 2; + rp_begin_info.clearValueCount = num_atts; rp_begin_info.pClearValues = clear_values; - /* VkSubmitInfo */ - stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - - memset(&submit_info, 0, sizeof submit_info); - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &ctx->cmd_buf; - - /* semaphores */ - if (semaphores) { - assert(semaphores->frame_ready); - assert(semaphores->frame_done); - - submit_info.pWaitDstStageMask = &stage_flags; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &semaphores->frame_done; - - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &semaphores->frame_ready; - } - - vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info); - vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE); + vkBeginCommandBuffer(cmd_buf, &cmd_begin_info); + vkCmdBeginRenderPass(cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE); viewport.x = x; viewport.y = y; @@ -1659,31 +1735,35 @@ vk_draw(struct vk_ctx *ctx, scissor.extent.width = w; scissor.extent.height = h; - vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport); - vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor); + vkCmdSetViewport(cmd_buf, 0, 1, &viewport); + vkCmdSetScissor(cmd_buf, 0, 1, &scissor); img_size.w = (float)w; img_size.h = (float)h; - vkCmdPushConstants(ctx->cmd_buf, - renderer->pipeline_layout, - VK_SHADER_STAGE_FRAGMENT_BIT, - 0, sizeof (struct vk_dims), - &img_size); + vkCmdPushConstants(cmd_buf, + renderer->pipeline_layout, + VK_SHADER_STAGE_FRAGMENT_BIT, + 0, sizeof (struct vk_dims), + &img_size); if (vbo) { - vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets); + vkCmdBindVertexBuffers(cmd_buf, 0, 1, &vbo->buf, offsets); } - vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); - int num_vertices = vbo ? renderer->vertex_info.num_verts : 4; - vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0); - vkCmdEndRenderPass(ctx->cmd_buf); - if (attachments) { + vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); + + num_vertices = vbo ? renderer->vertex_info.num_verts : 4; + vkCmdDraw(cmd_buf, num_vertices, 1, 0, 0); + vkCmdEndRenderPass(cmd_buf); + + free(clear_values); +#if 0 + if (atts) { VkImageMemoryBarrier *barriers = - calloc(n_attachments, sizeof(VkImageMemoryBarrier)); + calloc(num_atts, sizeof(VkImageMemoryBarrier)); VkImageMemoryBarrier *barrier = barriers; - for (uint32_t n = 0; n < n_attachments; n++, barrier++) { - struct vk_image_attachment *att = &attachments[n]; + for (uint32_t n = 0; n < num_atts; n++, barrier++) { + struct vk_attachment *att = &atts[n]; VkImageAspectFlagBits depth_stencil_flags = get_aspect_from_depth_format(att->props.format); bool is_depth = (depth_stencil_flags != 0); @@ -1708,35 +1788,69 @@ vk_draw(struct vk_ctx *ctx, barrier->subresourceRange.layerCount = 1; } - vkCmdPipelineBarrier(ctx->cmd_buf, + vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, - n_attachments, barriers); + num_atts, barriers); free(barriers); } +#endif + + vkEndCommandBuffer(cmd_buf); + return true; +} + +void +vk_draw(struct vk_ctx *ctx, + struct vk_semaphores *semaphores, + uint32_t num_buffers, + VkCommandBuffer *cmd_buf) +{ + VkSubmitInfo submit_info; + VkPipelineStageFlagBits stage_flags; + + stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + + /* VkSubmitInfo */ + memset(&submit_info, 0, sizeof submit_info); + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = num_buffers; + submit_info.pCommandBuffers = cmd_buf; + + /* semaphores */ + if (semaphores) { + assert(semaphores->frame_ready); + assert(semaphores->frame_done); + + submit_info.pWaitDstStageMask = &stage_flags; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &semaphores->frame_done; + + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &semaphores->frame_ready; + } - vkEndCommandBuffer(ctx->cmd_buf); if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { fprintf(stderr, "Failed to submit queue.\n"); } - if (!semaphores) - vkQueueWaitIdle(ctx->queue); + vkQueueWaitIdle(ctx->queue); } void vk_clear_color(struct vk_ctx *ctx, + VkCommandBuffer cmd_buf, struct vk_buf *vbo, struct vk_renderer *renderer, float *vk_fb_color, uint32_t vk_fb_color_count, struct vk_semaphores *semaphores, bool has_wait, bool has_signal, - struct vk_image_attachment *attachments, + struct vk_attachment *attachments, uint32_t n_attachments, float x, float y, float w, float h) @@ -1789,7 +1903,7 @@ vk_clear_color(struct vk_ctx *ctx, memset(&submit_info, 0, sizeof submit_info); submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &ctx->cmd_buf; + submit_info.pCommandBuffers = &cmd_buf; /* FIXME */ if (has_wait) { @@ -1809,21 +1923,21 @@ vk_clear_color(struct vk_ctx *ctx, img_range.baseArrayLayer = 0; img_range.layerCount = 1; - vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info); + vkBeginCommandBuffer(cmd_buf, &cmd_begin_info); vk_transition_image_layout(&attachments[0], - ctx->cmd_buf, + cmd_buf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_QUEUE_FAMILY_EXTERNAL, ctx->qfam_idx); - vkCmdClearColorImage(ctx->cmd_buf, + vkCmdClearColorImage(cmd_buf, attachments[0].obj.img, VK_IMAGE_LAYOUT_GENERAL, &clear_values[0].color, 1, &img_range); - vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBeginRenderPass(cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE); viewport.x = x; viewport.y = y; @@ -1835,12 +1949,12 @@ vk_clear_color(struct vk_ctx *ctx, scissor.extent.width = w; scissor.extent.height = h; - vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport); - vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor); + vkCmdSetViewport(cmd_buf, 0, 1, &viewport); + vkCmdSetScissor(cmd_buf, 0, 1, &scissor); - vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); + vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); - vkCmdEndRenderPass(ctx->cmd_buf); + vkCmdEndRenderPass(cmd_buf); if (attachments) { VkImageMemoryBarrier *barriers = @@ -1848,7 +1962,7 @@ vk_clear_color(struct vk_ctx *ctx, VkImageMemoryBarrier *barrier = barriers; for (uint32_t n = 0; n < n_attachments; n++, barrier++) { - struct vk_image_attachment *att = &attachments[n]; + struct vk_attachment *att = &attachments[n]; /* Insert barrier to mark ownership transfer. */ barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -1874,7 +1988,7 @@ vk_clear_color(struct vk_ctx *ctx, barrier->subresourceRange.layerCount = 1; } - vkCmdPipelineBarrier(ctx->cmd_buf, + vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, @@ -1884,7 +1998,7 @@ vk_clear_color(struct vk_ctx *ctx, free(barriers); } - vkEndCommandBuffer(ctx->cmd_buf); + vkEndCommandBuffer(cmd_buf); if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { fprintf(stderr, "Failed to submit queue.\n"); @@ -1922,25 +2036,18 @@ vk_create_swapchain(struct vk_ctx *ctx, return false; } - /* allocate and init an empty struct vk_swapchain */ - swapchain = malloc(sizeof *swapchain); memset(swapchain, 0, sizeof *swapchain); - swapchain->surface = surf; memset(&s_info, 0, sizeof s_info); s_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; s_info.flags = 0; - /* surface format */ if (!sc_select_format(ctx, surf, &s_info)) { fprintf(stderr, "Failed to determine the surface format.\n"); return false; } s_info.surface = surf; - - /* number of images */ s_info.minImageCount = surf_cap.minImageCount; - /* swapchain images dims */ { extent.width = width; extent.height = height; @@ -1950,8 +2057,6 @@ vk_create_swapchain(struct vk_ctx *ctx, } s_info.imageExtent = extent; s_info.imageArrayLayers = 1; - /* enable color attachment bit and transfer src and transfer dst bits - * too if they are supported */ { s_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) @@ -1964,16 +2069,15 @@ vk_create_swapchain(struct vk_ctx *ctx, /* we might want to use this function when we recreate the swapchain too */ s_info.preTransform = surf_cap.supportedTransforms & - VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ? - VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : - surf_cap.currentTransform; + VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ? + VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : + surf_cap.currentTransform; /* we could also write a sc_select_supported_composite_alpha * later but VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR is universally * supported */ s_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; s_info.clipped = VK_TRUE; - s_info.oldSwapchain = old_swapchain ? old_swapchain->swapchain : 0; if (vkCreateSwapchainKHR(ctx->dev, &s_info, 0, &swapchain->swapchain) != VK_SUCCESS) { @@ -1981,58 +2085,71 @@ vk_create_swapchain(struct vk_ctx *ctx, return false; } - /* if an existing swapchain is recreated we need to destroy - * the old swapchain and clean up the images */ - if (old_swapchain) { - for (i = 0; i < old_swapchain->num_images; i++) { - vkDestroyImageView(ctx->dev, old_swapchain->images[i].img_view, 0); - } - vk_destroy_swapchain(ctx, old_swapchain); + if (!swapchain->swapchain) { + fprintf(stderr, "The swapchain seems null\n"); + return false; } /* get the number of swapchain images and the swapchain images * and store the new swapchain images */ - vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, 0); - printf("number of swapchain images: %d\n", swapchain->num_images); + vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_atts, 0); + printf("number of swapchain images: %d\n", swapchain->num_atts); /* create images */ - s_images = malloc(swapchain->num_images * sizeof(VkImage)); - vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, s_images); + s_images = malloc(swapchain->num_atts * sizeof(VkImage)); + if (!s_images) { + fprintf(stderr, "Failed to allocate swapchain images.\n"); + return false; + } + + vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_atts, s_images); swapchain->image_fmt = s_info.imageFormat; - swapchain->images = malloc(swapchain->num_images * sizeof(struct vk_image_obj)); + swapchain->atts = malloc(swapchain->num_atts * sizeof swapchain->atts[0]); + if (!swapchain->atts) { + fprintf(stderr, "Failed to allocate swapchain images.\n"); + goto fail; + } + memset(swapchain->atts, 0, sizeof swapchain->atts[0]); memset(&sr, 0, sizeof sr); sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; sr.levelCount = 1; sr.layerCount = 1; - for (i = 0; i < swapchain->num_images; i++) { - swapchain->images[i].img = s_images[i]; - if (!(create_image_view(ctx, - swapchain->images[i].img, - VK_IMAGE_VIEW_TYPE_2D, - swapchain->image_fmt, - sr, - true, - &swapchain->images[i].img_view))) { - fprintf(stderr, "Fail to create an image view from the swapchain image: i=%d\n", i); - break; - } - if (i < swapchain->num_images - 1) { - int j; - for (j = 0; j < i; j++) { - vkDestroyImageView(ctx->dev, swapchain->images[i].img_view, 0); - } - return false; - } + for (i = 0; i < swapchain->num_atts; i++) { + /* we store the image */ + swapchain->atts[i].obj.img = s_images[i]; - memset(&swapchain->images[i].mobj, 0, sizeof swapchain->images[i].mobj); + /* filling attachment properties here where that info + * is available */ + + vk_fill_image_props(ctx, width, height, 1, + 1, 1, 1, + s_info.imageFormat, + 0, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + true, false, false, + &swapchain->atts[i].props); + swapchain->atts[i].props.usage = s_info.imageUsage; + + if (!create_image_view(ctx, s_images[i], + VK_IMAGE_VIEW_TYPE_2D, + s_info.imageFormat, sr, true, + &swapchain->atts[i].obj.img_view)) { + fprintf(stderr, "Failed to create image view for image: %d\n", i); + goto fail; + } } free(s_images); return true; + +fail: + free(s_images); + return false; } void @@ -2046,9 +2163,36 @@ vk_destroy_swapchain(struct vk_ctx *ctx, swapchain = 0; } +bool +vk_present_queue(struct vk_swapchain *swapchain, + VkQueue queue, + uint32_t image_idx, + VkSemaphore wait_sema) +{ + VkPresentInfoKHR pinfo; + + memset(&pinfo, 0, sizeof pinfo); + pinfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + pinfo.swapchainCount = 1; + pinfo.pImageIndices = &image_idx; + + if (wait_sema != VK_NULL_HANDLE) { + pinfo.pWaitSemaphores = &wait_sema; + pinfo.waitSemaphoreCount = 1; + } + + if (vkQueuePresentKHR(queue, &pinfo) != VK_SUCCESS) { + fprintf(stderr, "Failed to present queue.\n"); + return false; + } + + return true; +} + void vk_copy_image_to_buffer(struct vk_ctx *ctx, - struct vk_image_attachment *src_img, + VkCommandBuffer cmd_buf, + struct vk_attachment *src_img, struct vk_buf *dst_bo, float w, float h) { @@ -2064,12 +2208,12 @@ vk_copy_image_to_buffer(struct vk_ctx *ctx, memset(&submit_info, 0, sizeof submit_info); submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &ctx->cmd_buf; + submit_info.pCommandBuffers = &cmd_buf; - vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info); + vkBeginCommandBuffer(cmd_buf, &cmd_begin_info); if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) { vk_transition_image_layout(src_img, - ctx->cmd_buf, + cmd_buf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_QUEUE_FAMILY_EXTERNAL, @@ -2091,13 +2235,13 @@ vk_copy_image_to_buffer(struct vk_ctx *ctx, .imageExtent = { w, h, 1 } }; - vkCmdCopyImageToBuffer(ctx->cmd_buf, + vkCmdCopyImageToBuffer(cmd_buf, src_img->obj.img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_bo->buf, 1, ©_region); vk_transition_image_layout(src_img, - ctx->cmd_buf, + cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_QUEUE_FAMILY_EXTERNAL, @@ -2114,14 +2258,14 @@ vk_copy_image_to_buffer(struct vk_ctx *ctx, .size = VK_WHOLE_SIZE }; - vkCmdPipelineBarrier(ctx->cmd_buf, + vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags) 0, 0, NULL, 1, &write_finish_buffer_memory_barrier, 0, NULL); } - vkEndCommandBuffer(ctx->cmd_buf); + vkEndCommandBuffer(cmd_buf); if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { fprintf(stderr, "Failed to submit queue.\n"); @@ -2217,7 +2361,7 @@ vk_destroy_fences(struct vk_ctx *ctx, } void -vk_transition_image_layout(struct vk_image_attachment *img_att, +vk_transition_image_layout(struct vk_attachment *img_att, VkCommandBuffer cmd_buf, VkImageLayout old_layout, VkImageLayout new_layout, @@ -2225,7 +2369,7 @@ vk_transition_image_layout(struct vk_image_attachment *img_att, uint32_t dst_queue_fam_idx) { VkImageMemoryBarrier barrier; - struct vk_image_props props = img_att->props; + struct vk_att_props props = img_att->props; VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format); memset(&barrier, 0, sizeof barrier); diff --git a/src/vk.h b/src/vk.h index 259240b..dfe6aa6 100644 --- a/src/vk.h +++ b/src/vk.h @@ -12,7 +12,8 @@ struct vk_ctx VkDevice dev; VkCommandPool cmd_pool; - VkCommandBuffer cmd_buf; + VkCommandBuffer *cmd_buffers; + uint32_t num_cmd_buffers; VkQueue queue; int qfam_idx; @@ -21,6 +22,12 @@ struct vk_ctx uint8_t driverUUID[VK_UUID_SIZE]; }; +struct vk_cmd_buffer +{ + VkCommandBuffer buffer; + VkSubmitInfo submit_info; +}; + struct vk_swapchain { VkSwapchainKHR swapchain; @@ -31,11 +38,11 @@ struct vk_swapchain VkFormat image_fmt; VkExtent2D extent2d; - uint32_t num_images; - struct vk_image_obj *images; + uint32_t num_atts; + struct vk_attachment *atts; }; -struct vk_image_props +struct vk_att_props { uint32_t w; uint32_t h; @@ -52,6 +59,8 @@ struct vk_image_props VkImageLayout in_layout; VkImageLayout end_layout; + bool is_depth; + bool is_swapchain; bool need_export; }; @@ -69,9 +78,9 @@ struct vk_image_obj { struct vk_mem_obj mobj; }; -struct vk_image_attachment { +struct vk_attachment { struct vk_image_obj obj; - struct vk_image_props props; + struct vk_att_props props; }; struct vk_vertex_info @@ -114,15 +123,21 @@ struct vk_semaphores /* context */ -bool vk_init_ctx(struct vk_ctx *ctx); -bool vk_init_ctx_for_rendering(struct vk_ctx *ctx); -void vk_cleanup_ctx(struct vk_ctx *ctx); +bool vk_init_ctx(struct vk_ctx *ctx, + bool enable_layers); + +bool vk_init_ctx_for_rendering(struct vk_ctx *ctx, + bool enable_cache, + bool enable_layers); + +void vk_cleanup_ctx(struct vk_ctx *ctx, + bool enable_layers); /* images */ bool vk_create_image(struct vk_ctx *ctx, - struct vk_image_props *props, + struct vk_att_props *props, struct vk_image_obj *img_obj); void vk_destroy_image(struct vk_ctx *ctx, @@ -139,15 +154,10 @@ vk_fill_image_props(struct vk_ctx *ctx, VkImageTiling tiling, VkImageLayout in_layout, VkImageLayout end_layout, + bool is_swapchain, + bool is_depth, bool need_export, - struct vk_image_props *props); - -bool -vk_create_attachment_from_swapchain_image(struct vk_ctx *ctx, - VkImage *swapchain_img, - VkImageView *swapchain_view, - struct vk_image_props *swapchain_props, - struct vk_image_attachment *color_att); + struct vk_att_props *props); /* buffers */ @@ -203,10 +213,13 @@ vk_create_renderer(struct vk_ctx *ctx, unsigned int vs_size, const char *fs_src, unsigned int fs_size, + int w, int h, + uint32_t num_samples, bool enable_depth, bool enable_stencil, - struct vk_image_attachment *color_att, - struct vk_image_attachment *depth_att, + int num_color_att, + struct vk_attachment *color_att, + struct vk_attachment *depth_att, struct vk_vertex_info *vert_info, struct vk_renderer *renderer); @@ -215,27 +228,45 @@ vk_destroy_renderer(struct vk_ctx *ctx, struct vk_renderer *pipeline); /* draw */ +VkCommandBuffer +vk_create_cmd_buffer(struct vk_ctx *ctx); + +bool +vk_record_cmd_buffer(struct vk_ctx *ctx, + VkCommandBuffer cmd_buf, + struct vk_renderer *renderer, + struct vk_buf *vbo, + uint32_t vk_fb_color_count, + float *vk_fb_color, + uint32_t num_atts, + struct vk_attachment *atts, + float x, float y, + float w, float h); + +void +vk_reset_cmd_buf(struct vk_cmd_buffer *cmd_buf); + +void +vk_destroy_cmd_bufs(struct vk_ctx *ctx, + uint32_t num_buffers, + VkCommandBuffer *buffers); void vk_draw(struct vk_ctx *ctx, - struct vk_buf *vbo, - struct vk_renderer *renderer, - float *vk_fb_color, - uint32_t vk_fb_color_count, struct vk_semaphores *semaphores, - struct vk_image_attachment *attachments, - uint32_t n_attachments, - float x, float y, float w, float h); + uint32_t num_buffers, + VkCommandBuffer *cmd_buf); void vk_clear_color(struct vk_ctx *ctx, + VkCommandBuffer cmd_buf, struct vk_buf *vbo, struct vk_renderer *renderer, float *vk_fb_color, uint32_t vk_fb_color_count, struct vk_semaphores *semaphores, bool has_wait, bool has_signal, - struct vk_image_attachment *attachments, + struct vk_attachment *attachments, uint32_t n_attachments, float x, float y, float w, float h); @@ -252,16 +283,23 @@ void vk_destroy_swapchain(struct vk_ctx *ctx, struct vk_swapchain *swapchain); +bool +vk_present_queue(struct vk_swapchain *swapchain, + VkQueue queue, + uint32_t image_idx, + VkSemaphore wait_sema); + /* transitions */ void vk_copy_image_to_buffer(struct vk_ctx *ctx, - struct vk_image_attachment *src_img, + VkCommandBuffer cmd_buf, + struct vk_attachment *src_img, struct vk_buf *dst_bo, float w, float h); void -vk_transition_image_layout(struct vk_image_attachment *img_att, +vk_transition_image_layout(struct vk_attachment *img_att, VkCommandBuffer cmd_buf, VkImageLayout old_layout, VkImageLayout new_layout,