From: Eleni Maria Stea Date: Tue, 5 Oct 2021 16:37:52 +0000 (+0300) Subject: fixed swapchain sync for standard win, needs recreation at resize X-Git-Url: https://eleni.mutantstargoat.com/git/?p=vkrt;a=commitdiff_plain;h=739a8266145a78fdc015ac74c890474f023b1fd1 fixed swapchain sync for standard win, needs recreation at resize see abort in swapchain errors in main --- diff --git a/src/main.cc b/src/main.cc index ea70715..d642aab 100644 --- a/src/main.cc +++ b/src/main.cc @@ -19,8 +19,8 @@ #include "camera.h" /* defines */ - -#define FENCE_TIMEOUT 100000000000 +#define FRAME_LAG 2 +#define FENCE_TIMEOUT UINT64_MAX /**************************/ /* static glfw callbacks */ @@ -58,6 +58,9 @@ display(); static bool vk_init(); +static bool +vk_create_sync_objects(); + static void vk_cleanup(); @@ -88,13 +91,16 @@ static int win_h = 600; static bool vk_enable_layers = true; static struct vk_ctx vk_core; static VkSurfaceKHR vk_surf; + static struct vk_swapchain vk_chain; -static uint32_t vk_chain_idx; -static struct vk_semaphores vk_sema; +static uint32_t vk_current_image; +static int vk_frame_idx; +static std::vectorvk_framebuffers; /* for the moment: one cmd buffer per swapchain image */ static std::vectorvk_cmd_buffers; -static std::vectorvk_wait_fences; +static std::vectorvk_fences; +static struct vk_semaphores vk_semas[FRAME_LAG]; /* FIXME make them part of each object's functions/params */ static struct vk_renderer vk_rnd; @@ -102,65 +108,52 @@ static struct vk_attachment vk_depth_att; static float vk_fb_color[4] = { 0.0, 0.0, 0.5, 1.0 }; /* empty for as long as we hardcode the vertices in the vertex shader */ +#if 0 static struct vk_vertex_info vk_vert_info; +#endif int main(int argc, char** argv) { atexit(cleanup); + /*********************************************************** + * GLFW + ***********************************************************/ + if (!glfwInit()) { fprintf(stderr, "Failed to initialize GLFW.\n"); return 1; } - if (!init()) { - return 1; - } - -#if 0 - glfwGetWindowSize(win, &win_w, &win_h); - clb_reshape(win, win_w, win_h); -#endif - - while(!glfwWindowShouldClose(win)) { - glfwPollEvents(); - display(); - } - vkDeviceWaitIdle(vk_core.dev); - - return 0; -} - -/* static functions */ - -static bool -vk_init() -{ if (glfwVulkanSupported() != GLFW_TRUE) { fprintf(stderr, "Vulkan is not supported on this device.\n"); return false; } - /* create window */ - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - win = glfwCreateWindow(win_w, win_h, "helloworld rt", 0, 0); - - if (!win) { + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + if (!(win = glfwCreateWindow(win_w, win_h, "helloworld rt", 0, 0))) { fprintf(stderr, "Failed to create GLFW window\n"); return false; } glfwSetKeyCallback(win, clb_key); + glfwSetWindowSizeCallback(win, clb_reshape); + glfwSetCursorPosCallback(win, clb_motion); + glfwSetMouseButtonCallback(win, clb_mouse); - /* initialize Vulkan context (instance) */ + /*********************************************************** + * VULKAN context + ***********************************************************/ if (!vk_init_ctx_for_rendering(&vk_core, true, vk_enable_layers)) { fprintf(stderr, "Failed to initialize Vulkan context.\n"); return false; } - /* create (Xcb) surface */ + /*********************************************************** + * XCB/GLFW surface + ***********************************************************/ glfwGetFramebufferSize(win, &win_h, &win_h); if (glfwCreateWindowSurface(vk_core.inst, win, 0, &vk_surf) @@ -169,29 +162,67 @@ vk_init() return false; } - /* load shaders */ - int vsz, fsz; - char *vsdr = sdr_load("data/main.vert.spv", &vsz); - char *fsdr = sdr_load("data/main.frag.spv", &fsz); + /*********************************************************** + * Initialize Vulkan structs + ***********************************************************/ - /* create semaphores */ - if (!vk_create_semaphores(&vk_core, false, &vk_sema)) { - fprintf(stderr, "No semaphores were created.\n"); - goto fail; + if (!vk_init()) { + return 1; } + /*********************************************************** + * Initialize program objects, classes etc + ***********************************************************/ + + if (!init()) { + return 1; + } + + /*********************************************************** + * Rendering loop + ***********************************************************/ + + while(!glfwWindowShouldClose(win)) { + glfwPollEvents(); + display(); + } + + vkDeviceWaitIdle(vk_core.dev); + return 0; +} + +/* static functions */ + +static bool +vk_init() +{ /* create swapchain */ 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; + return false; } if (vk_chain.swapchain == VK_NULL_HANDLE) { fprintf(stderr, "Invalid swapchain handle.\n"); - goto fail; + return false; } - /* FIXME: this part is going to be part of each object's functions */ + if (!vk_create_sync_objects()) { + fprintf(stderr, "Failed to create sync objects.\n"); + return false; + } + + /* FIXME for the moment one cmd buf. + * But most probably I need to change this later. */ + VkCommandBuffer cmd_buf; + if (!(cmd_buf = vk_create_cmd_buffer(&vk_core))) { + fprintf(stderr, "Failed to create command buffer: %d.\n", 0); + return false; + } + vk_cmd_buffers.push_back(cmd_buf); + + /* FIXME: this part is going to be part of each object's + * renderpass and pipeline */ /* create depth attachment (for the moment we are going to use this * for all images */ @@ -209,78 +240,54 @@ vk_init() } if (!vk_create_image(&vk_core, &vk_depth_att.props, &vk_depth_att.obj)) { fprintf(stderr, "Failed to create depth attachment.\n"); - goto fail; + return false; + } + if(!vk_create_image_view(&vk_core, vk_depth_att.obj.img, VK_IMAGE_VIEW_TYPE_2D, + vk_depth_att.props.format, false, + &vk_depth_att.obj.img_view)) { + fprintf(stderr, "Failed to create image view for depth attachment.\n"); + return false; } + /* load shaders */ + int vsz, fsz; + char *vsdr = sdr_load("data/main.vert.spv", &vsz); + char *fsdr = sdr_load("data/main.frag.spv", &fsz); + /* create renderer */ 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)) { + true, false, + 1, &vk_chain.img_props, &vk_depth_att.props, + 0, &vk_rnd)) { goto fail; } - /* create cmd buffers */ - for (size_t i = 0; i < vk_chain.num_atts; i++) { - VkCommandBuffer cmd_buf; - VkFence fence; - if(!(vk_create_fence(&vk_core, &fence))) { - fprintf(stderr, "Failed to create fence: %d.\n", (int)i); - goto fail; - } - vk_wait_fences.push_back(fence); - - if (!(cmd_buf = vk_create_cmd_buffer(&vk_core))) { - fprintf(stderr, "Failed to create command buffer: %d.\n", (int)i); - goto fail; - } - - /* record cmd buffer FIXME: - * part of each objects draw? loop for each - * renderer */ - if (!vk_record_cmd_buffer(&vk_core, 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; - } - - vk_cmd_buffers.push_back(cmd_buf); + vk_framebuffers.resize(vk_chain.num_images, VK_NULL_HANDLE); + for (uint32_t i = 0; i < vk_chain.num_images; i++) { + if (!vk_create_framebuffer(&vk_core, + win_w, win_h, 1, + &vk_chain.views[i], + &vk_depth_att.obj.img_view, + vk_rnd.renderpass, + &vk_framebuffers[i])) + goto fail; } - vkResetFences(vk_core.dev, vk_wait_fences.size(), vk_wait_fences.data()); + /* record cmd buffer FIXME: + * should move this and make it part of each renderer + * also add all other stuff needed like uniforms + * descriptor sets spec constants push constants etc + * renderer + */ free(vsdr); free(fsdr); - /* set GLFW callbacks */ - - glfwSetWindowSizeCallback(win, clb_reshape); - - glfwSetCursorPosCallback(win, clb_motion); - glfwSetMouseButtonCallback(win, clb_mouse); - return true; fail: - for (size_t i = 0; i < vk_wait_fences.size(); i++) { - vk_destroy_fences(&vk_core, vk_wait_fences.size(), vk_wait_fences.data()); - } - vk_wait_fences.clear(); - - for (size_t i = 0; i < vk_cmd_buffers.size(); i++) { - vk_destroy_cmd_buffers(&vk_core, vk_cmd_buffers.size(), vk_cmd_buffers.data()); - } - vk_cmd_buffers.clear(); - - if (vk_depth_att.obj.img != VK_NULL_HANDLE) { - vk_destroy_image(&vk_core, &vk_depth_att.obj); - } - free(vsdr); free(fsdr); @@ -290,11 +297,6 @@ fail: static bool init() { - if (!vk_init()) { - fprintf(stderr, "Failed to initialize Vulkan structs.\n"); - return false; - } - camera = new OrbitCamera; return true; } @@ -307,28 +309,69 @@ cleanup() vk_cleanup(); } +/* FIXME */ static int count; static void display() { + vkWaitForFences(vk_core.dev, 1, &vk_fences[vk_frame_idx], VK_TRUE, UINT64_MAX); + vkResetFences(vk_core.dev, 1, &vk_fences[vk_frame_idx]); + + VkResult err; + do { + err = vkAcquireNextImageKHR(vk_core.dev, vk_chain.swapchain, + UINT64_MAX, + vk_semas[vk_frame_idx].frame_ready, + 0, &vk_current_image); + switch(err) { + case VK_ERROR_OUT_OF_DATE_KHR: + fprintf(stderr, "acquire next image error: VK_ERROR_OUT_OF_DATE_KHR.\n"); + abort(); + break; + case VK_SUBOPTIMAL_KHR: + fprintf(stderr, "AcquireNextImageKHR returned VK_SUBOPTIMAL_KHR, ignored.\n"); + abort(); + break; + case VK_ERROR_SURFACE_LOST_KHR: + vkDestroySurfaceKHR(vk_core.inst, vk_surf, 0); + if (glfwCreateWindowSurface(vk_core.inst, win, 0, &vk_surf) != + VK_SUCCESS) { + fprintf(stderr, "Failed to recreate GLFW/XCB surface.\n"); + } + abort(); + break; + default: + assert(!err); + break; + } + } while (err != VK_SUCCESS); + + /* FIXME update buffer data */ + if (!vk_record_cmd_buffer(&vk_core, vk_cmd_buffers[0], + &vk_rnd, 0, + 4, vk_fb_color, + vk_framebuffers[vk_current_image], + 2, 0, + 0, 0, win_w, win_h)) { + fprintf(stderr, "Failed to record command buffer.\n"); + abort(); + } + /* each object should have a command buffer renderpass etc? */ VkSubmitInfo sinfo; VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - vkAcquireNextImageKHR(vk_core.dev, vk_chain.swapchain, - UINT64_MAX, vk_sema.frame_ready, 0, &vk_chain_idx); - memset(&sinfo, 0, sizeof sinfo); sinfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; sinfo.waitSemaphoreCount = 1; - sinfo.pWaitSemaphores = &vk_sema.frame_ready; + sinfo.pWaitSemaphores = &vk_semas[vk_frame_idx].frame_ready; sinfo.pWaitDstStageMask = &wait_stages; sinfo.commandBufferCount = 1; - sinfo.pCommandBuffers = &vk_cmd_buffers[vk_chain_idx]; + sinfo.pCommandBuffers = &vk_cmd_buffers[0]; sinfo.signalSemaphoreCount = 1; - sinfo.pSignalSemaphores = &vk_sema.frame_done; + sinfo.pSignalSemaphores = &vk_semas[vk_frame_idx].frame_done; - if (vkQueueSubmit(vk_core.queue, 1, &sinfo, vk_wait_fences[vk_chain_idx]) != 0) { + if (vkQueueSubmit(vk_core.queue, 1, &sinfo, vk_fences[vk_frame_idx]) != 0) { fprintf(stderr, "Failed to submit draw commands.\n"); abort(); } @@ -338,38 +381,28 @@ display() abort(); } - if (vkWaitForFences(vk_core.dev, 1, &vk_wait_fences[vk_chain_idx], - VK_TRUE, FENCE_TIMEOUT) != VK_SUCCESS) { - fprintf(stderr, "Waiting for fence: %u failed.\n", vk_chain_idx); + if (!vk_queue_present(&vk_chain, vk_core.queue, vk_current_image, + vk_semas[vk_frame_idx].frame_done)) { abort(); } -#if 0 - 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 = &vk_chain_idx; -#endif - - if (!vk_queue_present(&vk_chain, vk_core.queue, vk_chain_idx, vk_sema.frame_done)) { - abort(); - } - vkResetFences(vk_core.dev, 1, &vk_wait_fences[vk_chain_idx]); + vk_frame_idx = (vk_frame_idx + 1) % FRAME_LAG; printf("display %d\n", count++); + printf("current image %u\n", vk_current_image); + printf("frame idx %d\n", vk_frame_idx); } static void vk_cleanup() { - vkQueueWaitIdle(vk_core.queue); - vk_destroy_image(&vk_core, &vk_depth_att.obj); vk_destroy_renderer(&vk_core, &vk_rnd); - vk_destroy_semaphores(&vk_core, &vk_sema); + + for (size_t i = 0; i < vk_framebuffers.size(); i++) { + vkDestroyFramebuffer(vk_core.dev, vk_framebuffers[i], 0); + } + vk_framebuffers.clear(); glfwDestroyWindow(win); @@ -382,11 +415,57 @@ vk_cleanup() return; vk_destroy_cmd_buffers(&vk_core, vk_cmd_buffers.size(), vk_cmd_buffers.data()); + vk_cmd_buffers.clear(); + + vk_destroy_fences(&vk_core, vk_fences.size(), vk_fences.data()); + vk_fences.clear(); + + for (int i = 0; i < FRAME_LAG; i++) + vk_destroy_semaphores(&vk_core, &vk_semas[i]); + + for (size_t i = 0; i < vk_cmd_buffers.size(); i++) + vk_destroy_cmd_buffers(&vk_core, vk_cmd_buffers.size(), vk_cmd_buffers.data()); + vk_cmd_buffers.clear(); + glfwTerminate(); vk_cleanup_ctx(&vk_core); } +static bool +vk_create_sync_objects() +{ + VkFenceCreateInfo finfo; + memset(&finfo, 0, sizeof finfo); + finfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + finfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + VkSemaphoreCreateInfo sinfo; + memset(&sinfo, 0, sizeof sinfo); + sinfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + vk_fences.resize(FRAME_LAG, VK_NULL_HANDLE); + + for (int i = 0; i < FRAME_LAG; i++) { + if (vkCreateFence(vk_core.dev, &finfo, 0, &vk_fences[i]) != VK_SUCCESS) { + fprintf(stderr, "Failed to create fence: %d\n", i); + return false; + } + + if (vkCreateSemaphore(vk_core.dev, &sinfo, 0, &vk_semas[i].frame_ready) != VK_SUCCESS) { + fprintf(stderr, "Failed to create frame_ready semaphore: %d\n", i); + return false; + } + + if (vkCreateSemaphore(vk_core.dev, &sinfo, 0, &vk_semas[i].frame_done) != VK_SUCCESS) { + fprintf(stderr, "Failed to create frame_done semaphore: %d\n", i); + return false; + } + } + + return true; +} + /* glfw callbacks */ static void @@ -398,7 +477,7 @@ clb_reshape(GLFWwindow *win, mproj = calc_projection_matrix(45, aspect, 0.5, 1000.0f); /* FIXME near and far clipping planes */ - vk_set_viewport(&vk_core, vk_cmd_buffers[vk_chain_idx], + vk_set_viewport(&vk_core, vk_cmd_buffers[0], 0, 0, win_w, win_h, 0.0f, 1.0f); win_w = width; win_h = height; diff --git a/src/vk.c b/src/vk.c index a62fc18..56d4c6e 100644 --- a/src/vk.c +++ b/src/vk.c @@ -148,7 +148,7 @@ create_instance(bool enable_layers) /* VkApplicationInfo */ memset(&app_info, 0, sizeof app_info); app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - app_info.pApplicationName = "vktest"; + app_info.pApplicationName = "hikikornd"; app_info.apiVersion = VK_API_VERSION_1_1; /* VkInstanceCreateInfo */ @@ -291,23 +291,25 @@ create_pipeline_cache(struct vk_ctx *ctx) return pcache; } -static VkRenderPass -create_renderpass(struct vk_ctx *ctx, - uint32_t num_color_atts, - struct vk_attachment *color_atts, - struct vk_attachment *depth_att) +bool +vk_create_renderpass(struct vk_ctx *ctx, + uint32_t num_color_atts, + struct vk_att_props *color_props, + struct vk_att_props *depth_props, + VkRenderPass *renderpass) { VkAttachmentDescription *att_dsc; VkAttachmentReference *att_rfc; /* one subpass for the moment: */ VkSubpassDescription subpass_dsc[1]; + VkSubpassDependency subpass_dep; + VkRenderPassCreateInfo rpass_info; int i; uint32_t num_atts = num_color_atts + 1; - bool has_layout = depth_att->props.in_layout != - VK_IMAGE_LAYOUT_UNDEFINED; + bool has_layout = depth_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]); @@ -317,10 +319,10 @@ create_renderpass(struct vk_ctx *ctx, /* 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].samples = get_num_samples(color_props[i].num_samples); + att_dsc[i].initialLayout = color_props[i].in_layout; + att_dsc[i].finalLayout = color_props[i].end_layout; + att_dsc[i].format = color_props[i].format; att_dsc[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; att_dsc[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -328,17 +330,17 @@ create_renderpass(struct vk_ctx *ctx, 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; + att_rfc[i].layout = color_props[i].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; + att_dsc[num_color_atts].samples = get_num_samples(depth_props->num_samples); + att_dsc[num_color_atts].initialLayout = depth_props->in_layout; + att_dsc[num_color_atts].finalLayout = depth_props->end_layout; + att_dsc[num_color_atts].format = depth_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 : @@ -357,6 +359,35 @@ create_renderpass(struct vk_ctx *ctx, subpass_dsc[0].pColorAttachments = &att_rfc[0]; subpass_dsc[0].pDepthStencilAttachment = &att_rfc[num_color_atts]; + /* The subpasses in a render pass automatically take care of + * image layout transitions. These transitions are controlled + * by subpass dependencies, which specify memory and execution + * dependencies between subpasses. We have only a single subpass + * right now, but the operations right before and right after + * this subpass also count as implicit "subpasses". There are two + * built-in dependencies that take care of the transition at the + * start of the render pass and at the end of the render pass, + * but the former does not occur at the right time. It assumes + * that the transition occurs at the start of the pipeline, + * but we haven't acquired the image yet at that point! There are + * two ways to deal with this problem. + * + * We could change the waitStages for the frame_ready semaphore + * to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT to ensure that the render + * passes don't begin until the image is available, or we can make + * the render pass wait for the + * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT stage. + */ + + /* VkSubpassDependency */ + memset(&subpass_dep, 0, sizeof subpass_dep); + subpass_dep.srcSubpass = VK_SUBPASS_EXTERNAL; + subpass_dep.dstSubpass = 0; + subpass_dep.srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + subpass_dep.srcAccessMask = 0; + subpass_dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + subpass_dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + /* VkRenderPassCreateInfo */ memset(&rpass_info, 0, sizeof rpass_info); rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; @@ -364,17 +395,23 @@ create_renderpass(struct vk_ctx *ctx, rpass_info.pAttachments = att_dsc; rpass_info.subpassCount = 1; rpass_info.pSubpasses = subpass_dsc; + rpass_info.dependencyCount = 1; + rpass_info.pDependencies = &subpass_dep; - VkRenderPass rpass; - if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) { + if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, renderpass) != VK_SUCCESS) { fprintf(stderr, "Failed to create renderpass.\n"); - rpass = VK_NULL_HANDLE; + *renderpass = VK_NULL_HANDLE; + + free(att_dsc); + free(att_rfc); + + return false; } free(att_dsc); free(att_rfc); - return rpass; + return true; } static inline VkImageType @@ -469,42 +506,7 @@ get_pipeline_stage_flags(const VkImageLayout layout) return 0; } -static bool -create_image_view(struct vk_ctx *ctx, - VkImage image, - VkImageViewType view_type, - VkFormat format, - VkImageSubresourceRange sr, - bool is_swapchain, - VkImageView *image_view) -{ - VkImageViewCreateInfo info; - - memset(&info, 0, sizeof info); - info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - info.image = image; - info.viewType = view_type; - info.viewType = VK_IMAGE_VIEW_TYPE_2D; - info.format = format; - info.subresourceRange = sr; - - if (is_swapchain) { - info.components.r = VK_COMPONENT_SWIZZLE_R; - info.components.g = VK_COMPONENT_SWIZZLE_G; - info.components.b = VK_COMPONENT_SWIZZLE_B; - info.components.a = VK_COMPONENT_SWIZZLE_A; - } - - if (vkCreateImageView(ctx->dev, &info, 0, image_view) != VK_SUCCESS) { - fprintf(stderr, "Failed to create image view.\n"); - image_view = VK_NULL_HANDLE; - - return false; - } - - return true; -} - +#if 0 static bool create_attachment_views(struct vk_ctx *ctx, int num_color_att, struct vk_attachment *color_att, @@ -513,43 +515,30 @@ create_attachment_views(struct vk_ctx *ctx, int num_color_att, VkImageSubresourceRange sr; int i; - /* depth attachments */ - memset(&sr, 0, sizeof sr); - sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format); - sr.baseMipLevel = 0; - sr.levelCount = 1; - sr.baseArrayLayer = 0; - sr.layerCount = 1; - - create_image_view(ctx, depth_att->obj.img, VK_IMAGE_VIEW_TYPE_2D, - depth_att->props.format, sr, false, - &depth_att->obj.img_view); + vk_create_image_view(ctx, depth_att->obj.img, VK_IMAGE_VIEW_TYPE_2D, + depth_att->props.format, false, + &depth_att->obj.img_view); memset(&sr, 0, sizeof sr); sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 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); + vk_create_image_view(ctx, color_att[i].obj.img, VK_IMAGE_VIEW_TYPE_2D, + color_att[i].props.format, + color_att[i].props.is_swapchain, + &color_att[i].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) +static bool +create_framebuffer_from_attachments(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; @@ -572,22 +561,23 @@ create_framebuffer(struct vk_ctx *ctx, fb_info.attachmentCount = num_atts; fb_info.pAttachments = atts; - if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS) - goto fail; + if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS) { + fprintf(stderr, "Failed to create framebuffer.\n"); + free(atts); + renderer->fb = VK_NULL_HANDLE; - free(atts); - return; + return false; + } -fail: - fprintf(stderr, "Failed to create framebuffer.\n"); free(atts); - renderer->fb = VK_NULL_HANDLE; + return true; } +#endif static VkShaderModule create_shader_module(struct vk_ctx *ctx, - const char *src, - unsigned int size) + const char *src, + unsigned int size) { VkShaderModuleCreateInfo sm_info; VkShaderModule sm; @@ -807,7 +797,8 @@ create_graphics_pipeline(struct vk_ctx *ctx, layout_info.pushConstantRangeCount = 1; layout_info.pPushConstantRanges = pc_range; - if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) { + if (vkCreatePipelineLayout(ctx->dev, &layout_info, + 0, &pipeline_layout) != VK_SUCCESS) { fprintf(stderr, "Failed to create pipeline layout\n"); renderer->pipeline = VK_NULL_HANDLE; goto fail; @@ -1074,7 +1065,8 @@ sc_validate_surface(struct vk_ctx *ctx, return false; } - if(vkGetPhysicalDeviceSurfaceSupportKHR(ctx->pdev, ctx->qfam_idx, surf, &supported) != VK_SUCCESS) { + if(vkGetPhysicalDeviceSurfaceSupportKHR(ctx->pdev, ctx->qfam_idx, + surf, &supported) != VK_SUCCESS) { fprintf(stderr, "Failed to validate surface.\n"); return false; } @@ -1095,7 +1087,9 @@ sc_select_format(struct vk_ctx *ctx, VkSurfaceFormatKHR *formats; uint32_t num_formats; - if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, 0) != VK_SUCCESS) { + if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, + surf, + &num_formats, 0) != VK_SUCCESS) { fprintf(stderr, "Failed to get the number of surface formats.\n"); return false; } @@ -1107,7 +1101,8 @@ sc_select_format(struct vk_ctx *ctx, formats = malloc(num_formats * sizeof *formats); - if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, formats) != VK_SUCCESS) { + if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, + formats) != VK_SUCCESS) { fprintf(stderr, "Failed to get the supported surface formats.\n"); return false; } @@ -1134,17 +1129,21 @@ sc_select_supported_present_modes(struct vk_ctx *ctx, uint32_t num_present_modes; /* find supported present modes */ - if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, 0) != VK_SUCCESS || !num_present_modes) { + if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, + &num_present_modes, 0) != VK_SUCCESS || !num_present_modes) { fprintf(stderr, "Failed to get the number of the supported presentation modes.\n"); return false; } present_modes = malloc(num_present_modes * sizeof *present_modes); - if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, present_modes) != VK_SUCCESS) { + if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, + &num_present_modes, + present_modes) != VK_SUCCESS) { fprintf(stderr, "Failed to get the number of supported presentation modes.\n"); return false; } - if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, + if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, + &num_present_modes, present_modes) != VK_SUCCESS) { fprintf(stderr, "Failed to get the supported presentation modes.\n"); return false; @@ -1276,15 +1275,20 @@ vk_cleanup_ctx(struct vk_ctx *ctx) } bool -vk_create_image(struct vk_ctx *ctx, - struct vk_att_props *props, - struct vk_image_obj *img) +vk_create_ext_image(struct vk_ctx *ctx, + struct vk_att_props *props, + struct vk_image_obj *img) { + VkExternalMemoryImageCreateInfo ext_img_info; VkImageCreateInfo img_info; + memset(&ext_img_info, 0, sizeof ext_img_info); + ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; + ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + memset(&img_info, 0, sizeof img_info); img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - img_info.pNext = 0; /* do something if external */ + img_info.pNext = &ext_img_info; img_info.imageType = get_image_type(props->h, props->depth); img_info.format = props->format; img_info.extent.width = props->w; @@ -1295,15 +1299,20 @@ vk_create_image(struct vk_ctx *ctx, props->num_layers : VK_SAMPLE_COUNT_1_BIT; img_info.samples = get_num_samples(props->num_samples); img_info.tiling = props->tiling; - img_info.usage = props->usage ? - props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - img_info.initialLayout = props->in_layout; + img_info.usage = props->usage; + img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + /* issue 17 of EXT_external_objects + * Required in OpenGL implementations that support + * ARB_texture_view, OES_texture_view, EXT_texture_view, + * or OpenGL 4.3 and above. + */ + img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS) goto fail; - if(!alloc_image_memory(ctx, props->need_export, img)) + if(!alloc_image_memory(ctx, true, img)) goto fail; return true; @@ -1316,57 +1325,35 @@ fail: return false; } -void -vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj) -{ - if (img_obj->img != VK_NULL_HANDLE) { - vkDestroyImage(ctx->dev, img_obj->img, 0); - img_obj->img = VK_NULL_HANDLE; - } - - if (img_obj->mobj.mem != VK_NULL_HANDLE) { - vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0); - img_obj->mobj.mem = VK_NULL_HANDLE; - } -} - bool -vk_create_ext_image(struct vk_ctx *ctx, - struct vk_att_props *props, struct vk_image_obj *img) +vk_create_image(struct vk_ctx *ctx, + struct vk_att_props *props, + struct vk_image_obj *img) { - VkExternalMemoryImageCreateInfo ext_img_info; VkImageCreateInfo img_info; - memset(&ext_img_info, 0, sizeof ext_img_info); - ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; - ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; - memset(&img_info, 0, sizeof img_info); img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - img_info.pNext = &ext_img_info; + img_info.pNext = 0; /* do something if external */ img_info.imageType = get_image_type(props->h, props->depth); img_info.format = props->format; img_info.extent.width = props->w; img_info.extent.height = props->h; img_info.extent.depth = props->depth; img_info.mipLevels = props->num_levels ? props->num_levels : 1; - img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT; + img_info.arrayLayers = props->num_layers ? + props->num_layers : VK_SAMPLE_COUNT_1_BIT; img_info.samples = get_num_samples(props->num_samples); img_info.tiling = props->tiling; - img_info.usage = props->usage; - img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + img_info.usage = props->usage ? + props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + img_info.initialLayout = props->in_layout; img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - /* issue 17 of EXT_external_objects - * Required in OpenGL implementations that support - * ARB_texture_view, OES_texture_view, EXT_texture_view, - * or OpenGL 4.3 and above. - */ - img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS) goto fail; - if(!alloc_image_memory(ctx, true, img)) + if(!alloc_image_memory(ctx, props->need_export, img)) goto fail; return true; @@ -1380,6 +1367,63 @@ fail: } bool +vk_create_image_view(struct vk_ctx *ctx, + VkImage image, + VkImageViewType view_type, + VkFormat format, + bool is_swapchain, + VkImageView *image_view) +{ + VkImageViewCreateInfo info; + VkImageSubresourceRange sr; + VkImageAspectFlagBits aspect = get_aspect_from_depth_format(format); + + /* VkSubresourceRange */ + memset(&sr, 0, sizeof sr); + sr.aspectMask = aspect ? aspect : VK_IMAGE_ASPECT_COLOR_BIT; + sr.levelCount = 1; + sr.layerCount = 1; + + memset(&info, 0, sizeof info); + info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + info.image = image; + info.viewType = view_type; + info.viewType = VK_IMAGE_VIEW_TYPE_2D; + info.format = format; + info.subresourceRange = sr; + + if (is_swapchain) { + info.components.r = VK_COMPONENT_SWIZZLE_R; + info.components.g = VK_COMPONENT_SWIZZLE_G; + info.components.b = VK_COMPONENT_SWIZZLE_B; + info.components.a = VK_COMPONENT_SWIZZLE_A; + } + + if (vkCreateImageView(ctx->dev, &info, 0, image_view) != VK_SUCCESS) { + fprintf(stderr, "Failed to create image view.\n"); + image_view = VK_NULL_HANDLE; + + return false; + } + + return true; +} + +void +vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj) +{ + if (img_obj->img != VK_NULL_HANDLE) { + vkDestroyImage(ctx->dev, img_obj->img, 0); + img_obj->img = VK_NULL_HANDLE; + } + + if (img_obj->mobj.mem != VK_NULL_HANDLE) { + vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0); + img_obj->mobj.mem = VK_NULL_HANDLE; + } +} + +bool vk_fill_image_props(struct vk_ctx *ctx, uint32_t w, uint32_t h, @@ -1420,6 +1464,76 @@ vk_fill_image_props(struct vk_ctx *ctx, return true; } +struct vk_attachment +vk_create_attachment_from_obj(struct vk_image_obj *obj, + struct vk_att_props *props) +{ + struct vk_attachment att; + + att.obj = *obj; + att.props = *props; + + return att; +} + +struct vk_attachment +vk_create_attachment(VkImage image, + VkImageView view, + struct vk_att_props *props) +{ + struct vk_attachment att; + + att.obj.img = image; + att.obj.img_view = view; + att.props = *props; + + memset(&att.obj.mobj, 0, sizeof att.obj.mobj); + + return att; +} + +bool +vk_create_framebuffer(struct vk_ctx *ctx, + int width, int height, + int num_color_atts, + VkImageView *color_views, + VkImageView *depth_view, + VkRenderPass rpass, + VkFramebuffer *fb) +{ + 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_views[i]; + } + atts[num_color_atts] = *depth_view; + + memset(&fb_info, 0, sizeof fb_info); + fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fb_info.renderPass = rpass; + 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, fb) != VK_SUCCESS) { + fprintf(stderr, "Failed to create framebuffer.\n"); + + fb = VK_NULL_HANDLE; + free(atts); + + return false; + } + + free(atts); + return true; +} + bool vk_create_renderer(struct vk_ctx *ctx, const char *vs_src, @@ -1431,41 +1545,37 @@ vk_create_renderer(struct vk_ctx *ctx, bool enable_depth, bool enable_stencil, int num_color_att, - struct vk_attachment *color_att, - struct vk_attachment *depth_att, + struct vk_att_props *color_props, + struct vk_att_props *depth_props, struct vk_vertex_info *vert_info, struct vk_renderer *renderer) { - memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info); - if (vert_info) - renderer->vertex_info = *vert_info; - /* create image views for each attachment */ +#if 0 if (!create_attachment_views(ctx, num_color_att, color_att, depth_att)) goto fail; +#endif - renderer->renderpass = create_renderpass(ctx, - num_color_att, - color_att, - depth_att); - - if (renderer->renderpass == VK_NULL_HANDLE) + VkRenderPass rpass; + if (!vk_create_renderpass(ctx, num_color_att, color_props, depth_props, + &rpass)) { goto fail; + } + renderer->renderpass = rpass; - create_framebuffer(ctx, - w, h, - num_color_att, color_att, - depth_att, renderer); - if (renderer->fb == VK_NULL_HANDLE) + VkShaderModule vs = create_shader_module(ctx, vs_src, vs_size); + if (vs == VK_NULL_HANDLE) goto fail; + renderer->vs = vs; - renderer->vs = create_shader_module(ctx, vs_src, vs_size); - if (renderer->vs == VK_NULL_HANDLE) + VkShaderModule fs = create_shader_module(ctx, fs_src, fs_size); + if (fs == VK_NULL_HANDLE) goto fail; + renderer->fs = fs; + + if (vert_info) + renderer->vertex_info = *vert_info; - renderer->fs = create_shader_module(ctx, fs_src, fs_size); - if (renderer->fs == VK_NULL_HANDLE) - goto fail; /* FIXME this is only for graphics atm */ if(!create_graphics_pipeline(ctx, w, h, @@ -1475,9 +1585,6 @@ vk_create_renderer(struct vk_ctx *ctx, enable_stencil, renderer)) goto fail; - if (renderer->pipeline == VK_NULL_HANDLE) - goto fail; - return true; fail: @@ -1505,11 +1612,6 @@ vk_destroy_renderer(struct vk_ctx *ctx, renderer->fs = VK_NULL_HANDLE; } - if (renderer->fb != VK_NULL_HANDLE) { - vkDestroyFramebuffer(ctx->dev, renderer->fb, 0); - renderer->fb = VK_NULL_HANDLE; - } - if (renderer->pipeline != VK_NULL_HANDLE) { vkDestroyPipeline(ctx->dev, renderer->pipeline, 0); renderer->pipeline = VK_NULL_HANDLE; @@ -1644,7 +1746,6 @@ vk_create_fence(struct vk_ctx *ctx, memset(&finfo, 0, sizeof finfo); finfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - finfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; if (vkCreateFence(ctx->dev, &finfo, 0, fence) != VK_SUCCESS) { fprintf(stderr, "Failed to create fence.\n"); @@ -1667,7 +1768,8 @@ vk_create_cmd_buffer(struct vk_ctx *ctx) alloc_info.commandBufferCount = 1; alloc_info.commandPool = ctx->cmd_pool; - if (vkAllocateCommandBuffers(ctx->dev, &alloc_info, &cmd_buf) != VK_SUCCESS) + if (vkAllocateCommandBuffers(ctx->dev, &alloc_info, + &cmd_buf) != VK_SUCCESS) return 0; return cmd_buf; @@ -1680,6 +1782,7 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, struct vk_buf *vbo, uint32_t vk_fb_color_count, float *vk_fb_color, + VkFramebuffer fb, uint32_t num_atts, struct vk_attachment *atts, float x, float y, @@ -1696,14 +1799,9 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, 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; - } - create_cmd_buf = true; + fprintf(stderr, "Can't record an empty command buffer.\n"); + return false; } /* VkCommandBufferBeginInfo */ @@ -1735,7 +1833,7 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, memset(&rp_begin_info, 0, sizeof rp_begin_info); rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rp_begin_info.renderPass = renderer->renderpass; - rp_begin_info.framebuffer = renderer->fb; + rp_begin_info.framebuffer = fb; rp_begin_info.renderArea = rp_area; rp_begin_info.clearValueCount = num_atts; rp_begin_info.pClearValues = clear_values; @@ -1768,7 +1866,8 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, vkCmdBindVertexBuffers(cmd_buf, 0, 1, &vbo->buf, offsets); } - vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); + 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); @@ -1833,8 +1932,6 @@ vk_draw(struct vk_ctx *ctx, 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; @@ -1846,6 +1943,27 @@ vk_draw(struct vk_ctx *ctx, assert(semaphores->frame_ready); assert(semaphores->frame_done); + /* The subpasses in a render pass automatically take care of + * image layout transitions. These transitions are controlled + * by subpass dependencies, which specify memory and execution + * dependencies between subpasses. We have only a single subpass + * right now, but the operations right before and right after + * this subpass also count as implicit "subpasses". There are two + * built-in dependencies that take care of the transition at the + * start of the render pass and at the end of the render pass, + * but the former does not occur at the right time. It assumes + * that the transition occurs at the start of the pipeline, + * but we haven't acquired the image yet at that point! There are + * two ways to deal with this problem. + * + * We could change the waitStages for the frame_ready semaphore + * to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT to ensure that the render + * passes don't begin until the image is available, or we can make + * the render pass wait for the + * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT stage. + */ + stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + submit_info.pWaitDstStageMask = &stage_flags; submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = &semaphores->frame_done; @@ -1855,7 +1973,8 @@ vk_draw(struct vk_ctx *ctx, } - if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { + if (vkQueueSubmit(ctx->queue, 1, &submit_info, + VK_NULL_HANDLE) != VK_SUCCESS) { fprintf(stderr, "Failed to submit queue.\n"); abort(); } @@ -1873,6 +1992,7 @@ vk_clear_color(struct vk_ctx *ctx, struct vk_renderer *renderer, float *vk_fb_color, uint32_t vk_fb_color_count, + VkFramebuffer fb, struct vk_semaphores *semaphores, bool has_wait, bool has_signal, struct vk_attachment *attachments, @@ -1917,7 +2037,7 @@ vk_clear_color(struct vk_ctx *ctx, memset(&rp_begin_info, 0, sizeof rp_begin_info); rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rp_begin_info.renderPass = renderer->renderpass; - rp_begin_info.framebuffer = renderer->fb; + rp_begin_info.framebuffer = fb; rp_begin_info.renderArea = rp_area; rp_begin_info.clearValueCount = 2; rp_begin_info.pClearValues = clear_values; @@ -1977,7 +2097,8 @@ vk_clear_color(struct vk_ctx *ctx, vkCmdSetViewport(cmd_buf, 0, 1, &viewport); vkCmdSetScissor(cmd_buf, 0, 1, &scissor); - vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); + vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, + renderer->pipeline); vkCmdEndRenderPass(cmd_buf); @@ -1993,7 +2114,7 @@ vk_clear_color(struct vk_ctx *ctx, barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; bool is_depth = - get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE; + get_aspect_from_depth_format(att->props.format) != 0; barrier->oldLayout = is_depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : @@ -2025,7 +2146,8 @@ vk_clear_color(struct vk_ctx *ctx, vkEndCommandBuffer(cmd_buf); - if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { + if (vkQueueSubmit(ctx->queue, 1, &submit_info, + VK_NULL_HANDLE) != VK_SUCCESS) { fprintf(stderr, "Failed to submit queue.\n"); } @@ -2071,9 +2193,7 @@ vk_create_swapchain(struct vk_ctx *ctx, VkSurfaceCapabilitiesKHR surf_cap; VkSwapchainCreateInfoKHR s_info; VkExtent2D extent; - VkImageSubresourceRange sr; - VkImage *s_images; - int i; + int i, j; if (!sc_validate_surface(ctx, surf)) { fprintf(stderr, "Failed to validate surface!\n"); @@ -2144,62 +2264,47 @@ vk_create_swapchain(struct vk_ctx *ctx, /* get the number of swapchain images and the swapchain images * and store the new swapchain images */ - vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_atts, 0); - printf("number of swapchain images: %d\n", swapchain->num_atts); + vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, + &swapchain->num_images, 0); + printf("number of swapchain images: %d\n", swapchain->num_images); - /* create 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); + /* get the images */ + swapchain->images = (VkImage*)alloca(swapchain->num_images * sizeof(VkImage)); + vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, + &swapchain->num_images, + swapchain->images); + /* create attributes from those images */ swapchain->image_fmt = s_info.imageFormat; - 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_atts; i++) { - /* we store the image */ - swapchain->atts[i].obj.img = s_images[i]; - - /* 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)) { + 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->img_props); + + swapchain->img_props.usage = s_info.imageUsage; + swapchain->views = malloc(swapchain->num_images * sizeof(VkImageView)); + + for (i = 0; i < swapchain->num_images; i++) { + if (!vk_create_image_view(ctx, swapchain->images[i], + VK_IMAGE_VIEW_TYPE_2D, + s_info.imageFormat, true, + &swapchain->views[i])) { fprintf(stderr, "Failed to create image view for image: %d\n", i); goto fail; } } - free(s_images); return true; fail: - free(s_images); + for (j = 0; j < i; j++) { + vkDestroyImageView(ctx->dev, swapchain->views[j], 0); + } return false; } @@ -2207,6 +2312,10 @@ void vk_destroy_swapchain(struct vk_ctx *ctx, struct vk_swapchain *swapchain) { + int i; + for (i = 0; i < swapchain->num_images; i++) { + vkDestroyImageView(ctx->dev, swapchain->views[i], 0); + } vkDestroySwapchainKHR(ctx->dev, swapchain->swapchain, 0); } @@ -2227,6 +2336,8 @@ vk_queue_present(struct vk_swapchain *swapchain, pinfo.pWaitSemaphores = &wait_sema; pinfo.waitSemaphoreCount = 1; + /* FIXME: add code for VK_KHR_incremental_present_enabled!! */ + if (vkQueuePresentKHR(queue, &pinfo) != VK_SUCCESS) { fprintf(stderr, "Failed to present queue.\n"); return false; @@ -2356,10 +2467,11 @@ void vk_destroy_semaphores(struct vk_ctx *ctx, struct vk_semaphores *semaphores) { - if (semaphores->frame_ready) - vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0); - if (semaphores->frame_done) - vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0); + vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0); + semaphores->frame_ready = VK_NULL_HANDLE; + + vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0); + semaphores->frame_done = VK_NULL_HANDLE; } bool diff --git a/src/vk.h b/src/vk.h index 5adfbd7..58a88ef 100644 --- a/src/vk.h +++ b/src/vk.h @@ -22,19 +22,6 @@ struct vk_ctx uint8_t driverUUID[VK_UUID_SIZE]; }; -struct vk_swapchain -{ - VkSwapchainKHR swapchain; - VkSurfaceFormatKHR surf_fmt; - - /* image properties */ - VkFormat image_fmt; - VkExtent2D extent2d; - - uint32_t num_atts; - struct vk_attachment *atts; -}; - struct vk_att_props { uint32_t w; @@ -57,6 +44,25 @@ struct vk_att_props bool need_export; }; +struct vk_swapchain +{ + VkSwapchainKHR swapchain; + VkSurfaceFormatKHR surf_fmt; + + /* image properties */ + /* FIXME: do I really need those 2?*/ + VkFormat image_fmt; + VkExtent2D extent2d; + + struct vk_att_props img_props; + + uint32_t num_images; + VkImage *images; + VkImageView *views; +}; + +/* for allocated images */ + struct vk_mem_obj { VkDeviceMemory mem; VkDeviceSize mem_sz; @@ -97,7 +103,6 @@ struct vk_renderer VkRenderPass renderpass; VkShaderModule vs; VkShaderModule fs; - VkFramebuffer fb; struct vk_vertex_info vertex_info; }; @@ -130,6 +135,10 @@ bool vk_init_ctx_for_rendering(struct vk_ctx *ctx, void vk_cleanup_ctx(struct vk_ctx *ctx); /* images */ +bool +vk_create_ext_image(struct vk_ctx *ctx, + struct vk_att_props *props, + struct vk_image_obj *img); bool vk_create_image(struct vk_ctx *ctx, @@ -140,6 +149,14 @@ vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj); bool +vk_create_image_view(struct vk_ctx *ctx, + VkImage image, + VkImageViewType view_type, + VkFormat format, + bool is_swapchain, + VkImageView *image_view); + +bool vk_fill_image_props(struct vk_ctx *ctx, uint32_t w, uint32_t h, uint32_t depth, @@ -155,6 +172,15 @@ vk_fill_image_props(struct vk_ctx *ctx, bool need_export, struct vk_att_props *props); +struct vk_attachment +vk_create_attachment_from_obj(struct vk_image_obj *obj, + struct vk_att_props *props); + +struct vk_attachment +vk_create_attachment(VkImage image, + VkImageView view, + struct vk_att_props *props); + /* buffers */ bool @@ -196,6 +222,21 @@ vk_destroy_fences(struct vk_ctx *ctc, VkFence *fences); /* renderer */ +bool +vk_create_framebuffer(struct vk_ctx *ctx, + int width, int height, + int num_color_atts, + VkImageView *color_views, + VkImageView *depth_view, + VkRenderPass rb, + VkFramebuffer *fb); + +bool +vk_create_renderpass(struct vk_ctx *ctx, + uint32_t num_color_atts, + struct vk_att_props *color_props, + struct vk_att_props *depth_props, + VkRenderPass *renderpass); bool vk_create_renderer(struct vk_ctx *ctx, @@ -208,8 +249,8 @@ vk_create_renderer(struct vk_ctx *ctx, bool enable_depth, bool enable_stencil, int num_color_att, - struct vk_attachment *color_att, - struct vk_attachment *depth_att, + struct vk_att_props *color_props, + struct vk_att_props *depth_props, struct vk_vertex_info *vert_info, struct vk_renderer *renderer); @@ -232,6 +273,7 @@ vk_record_cmd_buffer(struct vk_ctx *ctx, struct vk_buf *vbo, uint32_t vk_fb_color_count, float *vk_fb_color, + VkFramebuffer fb, uint32_t num_atts, struct vk_attachment *atts, float x, float y, @@ -256,6 +298,7 @@ vk_clear_color(struct vk_ctx *ctx, struct vk_renderer *renderer, float *vk_fb_color, uint32_t vk_fb_color_count, + VkFramebuffer fb, struct vk_semaphores *semaphores, bool has_wait, bool has_signal, struct vk_attachment *attachments,