X-Git-Url: https://eleni.mutantstargoat.com/git/?p=vkrt;a=blobdiff_plain;f=src%2Fmain.cc;h=5ec96d4cc7c9ccaf78ea34dd50d34c1c531eedb8;hp=af4277c20421d870a7884a345fc76f55f0a78a69;hb=c7de7f04077b07757ffef63ce6771a9d561945d5;hpb=6c8e0d1dcf1e08982b54a1b2d2e914e409e09386 diff --git a/src/main.cc b/src/main.cc index af4277c..5ec96d4 100644 --- a/src/main.cc +++ b/src/main.cc @@ -2,14 +2,28 @@ #define GLFW_INCLUDE_VULKAN #include + +#include #include #include +#include + +#include + +/* extern "C": vulkan framework */ #include "vk.h" #include "util.h" +/* C++ */ +#include "camera.h" +/* defines */ +#define FENCE_TIMEOUT UINT64_MAX + +/**************************/ /* static glfw callbacks */ +/**************************/ static void clb_key(GLFWwindow *win, int key, int scancode, int action, int mods); @@ -17,137 +31,197 @@ clb_key(GLFWwindow *win, int key, int scancode, int action, int mods); static void clb_reshape(GLFWwindow *win, int width, int height); +static void +clb_motion(GLFWwindow *win, double x, double y); + +static void +clb_mouse(GLFWwindow *win, int button, int action, int mods); + +/**************************/ /* static functions */ +/**************************/ + +/* init, cleanup, display */ static bool -init(void); +init(); + +static void +cleanup(); static void -cleanup(void); +display(); + +/* vulkan, glfw */ + +static bool +vk_init(); + +static bool +vk_create_sync_objects(); static void -display(void); +vk_cleanup(); -/* static variables */ +/***************************/ +/* static/global variables */ +/***************************/ static GLFWwindow *win; -static bool redraw_pending; +/* static bool redraw_pending; */ +static bool move_camera; -static bool vk_enable_layers = true; +/* camera */ +static float cam_phi = 25; +static float cam_theta = 0; +static float cam_dist = 16; +static Vec3 cam_pos; + +static OrbitCamera *camera; +static float aspect; +static Mat4 mproj; + +/* win etc */ static int win_w = 800; static int win_h = 600; +/* vulkan */ +static bool vk_enable_layers = true; static struct vk_ctx vk_core; static VkSurfaceKHR vk_surf; -static struct vk_renderer vk_rnd; + static struct vk_swapchain vk_chain; -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_fences; +static struct vk_semaphores *vk_semas; + +/* FIXME make them part of each object's functions/params */ +static struct vk_renderer vk_rnd; 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 */ +#if 0 static struct vk_vertex_info vk_vert_info; +#endif int main(int argc, char** argv) { atexit(cleanup); - if (!init()) { - return 1; - } - - /* reshape window once just in case */ - - glfwGetWindowSize(win, &win_w, &win_h); - clb_reshape(win, win_w, win_h); - - /* event loop */ - redraw_pending = true; - - while(!glfwWindowShouldClose(win)) { - glfwWaitEvents(); - if (redraw_pending) { - redraw_pending = false; - display(); - } - } - - return 0; -} - -/* static functions */ - -static bool -init(void) -{ - char *vsdr = 0; - char *fsdr = 0; - int vsz, fsz; - - /* initialize GLFW */ + /*********************************************************** + * GLFW + ***********************************************************/ if (!glfwInit()) { fprintf(stderr, "Failed to initialize GLFW.\n"); - return false; + return 1; } if (glfwVulkanSupported() != GLFW_TRUE) { fprintf(stderr, "Vulkan is not supported on this device.\n"); - return false; + return 1; } - /* 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; + return 1; } 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; + return 1; } - /* create (Xcb) surface */ + /*********************************************************** + * XCB/GLFW surface + ***********************************************************/ glfwGetFramebufferSize(win, &win_h, &win_h); if (glfwCreateWindowSurface(vk_core.inst, win, 0, &vk_surf) != VK_SUCCESS) { fprintf(stderr, "Failed to create XCB surface.\n"); - return false; + return 1; } - /* create semaphores */ - if (!vk_create_semaphores(&vk_core, false, &vk_sema)) { - fprintf(stderr, "No semaphores were created.\n"); - goto fail; + /*********************************************************** + * Initialize Vulkan structs + ***********************************************************/ + + 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; + } + + 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); - /* create shaders */ - vsdr = sdr_load("data/main.vert.spv", &vsz); - fsdr = sdr_load("data/main.frag.spv", &fsz); + /* 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 */ @@ -165,47 +239,51 @@ init(void) } 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 buffer */ - if ((vk_cmd_buf = vk_create_cmd_buffer(&vk_core)) == VK_NULL_HANDLE) { - fprintf(stderr, "Failed to create command buffer.\n"); + 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; } - /* 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; - } + /* 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: @@ -215,87 +293,256 @@ fail: return false; } +static bool +init() +{ + camera = new OrbitCamera; + return true; +} + +static void +cleanup() +{ + delete camera; + + vk_cleanup(); +} + +/* FIXME */ +static int count; static void -display(void) +display() { - uint32_t img_idx; + 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, + 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; - 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.pWaitSemaphores = &vk_semas[vk_frame_idx].frame_ready; sinfo.pWaitDstStageMask = &wait_stages; sinfo.commandBufferCount = 1; - sinfo.pCommandBuffers = &vk_cmd_buf; + 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, 0) != 0) { + if (vkQueueSubmit(vk_core.queue, 1, &sinfo, vk_fences[vk_frame_idx]) != 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; + if (vkQueueWaitIdle(vk_core.queue) != VK_SUCCESS) { + fprintf(stderr, "Failed to wait idle.\n"); + abort(); + } - vkQueuePresentKHR(vk_core.queue, &pinfo); + if (!vk_queue_present(&vk_chain, vk_core.queue, vk_current_image, + vk_semas[vk_frame_idx].frame_done)) { + abort(); + } + + vk_frame_idx = (vk_frame_idx + 1) % (vk_chain.num_images - 1); + + printf("display %d\n", count++); + printf("current image %u\n", vk_current_image); + printf("frame idx %d\n", vk_frame_idx); } static void -cleanup(void) +vk_cleanup() { - vkQueueWaitIdle(vk_core.queue); - - if (vk_cmd_buf != VK_NULL_HANDLE) { - vkResetCommandBuffer(vk_cmd_buf, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); - } + int num_images = vk_chain.num_images - 1; vk_destroy_image(&vk_core, &vk_depth_att.obj); - vk_destroy_semaphores(&vk_core, &vk_sema); vk_destroy_renderer(&vk_core, &vk_rnd); + for (size_t i = 0; i < vk_framebuffers.size(); i++) { + vkDestroyFramebuffer(vk_core.dev, vk_framebuffers[i], 0); + } + vk_framebuffers.clear(); + + glfwDestroyWindow(win); + if (vk_chain.swapchain) { vk_destroy_swapchain(&vk_core, &vk_chain); vkDestroySurfaceKHR(vk_core.inst, vk_surf, 0); } - glfwDestroyWindow(win); + if (vk_enable_layers) + return; - if (!vk_enable_layers) - vkFreeCommandBuffers(vk_core.dev, vk_core.cmd_pool, 1, &vk_cmd_buf); + vk_destroy_cmd_buffers(&vk_core, vk_cmd_buffers.size(), vk_cmd_buffers.data()); + vk_cmd_buffers.clear(); - vk_cleanup_ctx(&vk_core, vk_enable_layers); + vk_destroy_fences(&vk_core, vk_fences.size(), vk_fences.data()); + vk_fences.clear(); + + for (int i = 0; i < num_images; i++) + vk_destroy_semaphores(&vk_core, &vk_semas[i]); + free(vk_semas); + + 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(vk_chain.num_images - 1, VK_NULL_HANDLE); + + vk_semas = (vk_semaphores *)malloc(sizeof(vk_semaphores) * (vk_chain.num_images - 1)); + for (uint32_t i = 0; i < (vk_chain.num_images - 1); 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 +clb_reshape(GLFWwindow *win, + int width, + int height) +{ + aspect = (float)width / (float)height; + mproj = calc_projection_matrix(45, aspect, 0.5, 1000.0f); + + /* FIXME near and far clipping planes */ + 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; +} + +static void clb_key(GLFWwindow *win, int key, int scancode, int action, int mods) { + if (action == GLFW_REPEAT) return; + if (action == GLFW_PRESS) { switch(key) { case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(win, GLFW_TRUE); - return; + exit(0); + case ' ': + move_camera = !move_camera; + break; + default: + break; } } } +static double prev_x, prev_y; +static bool button[8]; + +static void +clb_motion(GLFWwindow *win, + double x, + double y) +{ + double dx = x - prev_x; + double dy = y - prev_y; + + prev_x = x; + prev_y = y; + + if(button[0]) { + cam_theta += dx * 0.5; + cam_phi += dy * 0.5; + + if(cam_phi < 0) + cam_phi = 0; + if(cam_phi > 90) + cam_phi = 90; + } + + if(button[1]) { + cam_dist += dy * 0.1; + if(cam_dist < 0.0) { + cam_dist = 0.0; + } + } +} + static void -clb_reshape(GLFWwindow *win, int width, int height) +clb_mouse(GLFWwindow *win, + int button, + int action, + int mods) { }