X-Git-Url: https://eleni.mutantstargoat.com/git/?p=vkrt;a=blobdiff_plain;f=src%2Fmain.cc;h=d642aab00041230d197096fed0c7493b6a3b8714;hp=ea7071534a2822b04486f1e0d85ab22be47e07bb;hb=739a8266145a78fdc015ac74c890474f023b1fd1;hpb=35f7d10bf03cc666b551490bcae87ac389d63cb7 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;