backup - needs fixing
[demo] / src / vulkan / vk.cc
index 3d9862d..0e3725b 100644 (file)
-#include "vulkan/vk.h"
-extern GLFWwindow win;
+#define GLFW_INCLUDE_VULKAN
+#include <GLFW/glfw3.h>
+
+#include <alloca.h>
+#include <stdio.h>
+#include <string.h>
+#include <string>
+#include <vector>
+
+#include <gmath/gmath.h>
+
+#include "gfxapi.h"
+#include "vkutil.h"
+
+/* global variables */
+extern GLFWwindow *win;
+extern int win_w;
+extern int win_h;
+
+VkCommandBuffer *swapchain_cmd_bufs;
+
+/* static functions */
+static void error_callback(int error, const char *descr);
+static void clear(float r, float g, float b);
+static void viewport(int x, int y, int width, int height);
+static void zbuffer(bool enable);
+static void cull_face(Gfx_cull_face cf);
+static void reshape(int width, int height);
+static void swapbuffers();
+static void begin_drawing();
+static void end_drawing();
+
+static bool create_swapchain_cmd_bufs(VkCommandPool vkcmdpool);
+static bool record_cmd_clear(float r, float g, float b);
 
 bool init_vulkan()
 {
+       gfx_clear = clear;
+       gfx_viewport = viewport;
+       gfx_zbuffer = zbuffer;
+       gfx_cull_face = cull_face;
+       gfx_reshape = reshape;
+       gfx_swapbuffers = swapbuffers;
+       gfx_begin_drawing = begin_drawing;
+       gfx_end_drawing = end_drawing;
+
+       if(!glfwInit()) {
+               fprintf(stderr, "Failed to initialize GLFW.\n");
+               return false;
+       }
+
+       if(!glfwVulkanSupported()) {
+               fprintf(stderr, "No Vulkan support on the device.\n");
+               return false;
+       }
+
+       glfwSetErrorCallback(error_callback);
+
+       if(!vku_create_device()) {
+               fprintf(stderr, "Failed to initialize vulkan.\n");
+               return false;
+       }
+
+       if(!glfwGetPhysicalDevicePresentationSupport(vkinst, vkpdev, vkqfamily)) {
+               fprintf(stderr, "Presentation support not found.\n");
+               return false;
+       }
+
+       glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+       if(!(win = glfwCreateWindow(win_w, win_h, "vkcow", 0, 0))) {
+               fprintf(stderr, "Failed to create window.\n");
+               return false;
+       }
+
+       if(VkResult err = glfwCreateWindowSurface(vkinst, win, 0, &vksurface)) {
+               fprintf(stderr, "Failed to create KHR surface: %s\n", vku_get_vulkan_error_str(err));
+               return false;
+       }
+
+       if(!vku_create_semaphores())
+               return false;
+
+       if(!(vkswapchain = vku_create_swapchain(vksurface, win_w, win_h, 2,
+                                               VK_PRESENT_MODE_FIFO_KHR, 0))) {
+               fprintf(stderr, "Failed to create swapchain.\n");
+               return false;
+       }
+
+       vkswapchain_images = vku_get_swapchain_images(vkswapchain, &vknum_swapchain_images);
+       if(!vkswapchain_images) {
+               fprintf(stderr, "Failed to get swapchain images.\n");
+               return false;
+       }
+
+       /*      vkswapchain_views = vku_create_image_views(vkswapchain_images, vknum_swapchain_images);
+               if(!vkswapchain_views) {
+                       fprintf(stderr, "Failed to create swapchain image views.\n");
+                       delete [] vkswapchain_images;
+                       return false;
+               }
+       */
+       if(!create_swapchain_cmd_bufs(vkcmdpool)) {
+               return false;
+       }
+
+       if(!record_cmd_clear(1.0, 0.1, 0.1))
+               return false;
+
        return true;
 }
 
 void cleanup_vulkan()
 {
+       vkFreeCommandBuffers(vkdev, vkcmdpool, vknum_swapchain_images, swapchain_cmd_bufs);
+       if(win) {
+               glfwDestroyWindow(win);
+       }
+       glfwTerminate();
+
+       //TODOs according to the book:
+       // 1- make sure all threads have been terminated (when I add threads)
+       vku_cleanup();
 }
 
-GLFWwindow *create_vulkan_window()
+static void error_callback(int error, const char *description)
 {
-       return 0;
+       fprintf(stderr, "GLFW error %d: %s.\n", error, description);
 }
 
-void display_vulkan()
+static void reshape(int width, int height)
 {
+       VkSwapchainKHR sc;
+       if(!(sc = vku_create_swapchain(vksurface, width, height, 2, VK_PRESENT_MODE_FIFO_KHR,
+                                      vkswapchain))) {
+               fprintf(stderr, "Failed to create %dx%d double-buffered swapchain\n", width, height);
+               return;
+       }
+       vkswapchain = sc;
+
+       delete [] vkswapchain_images;
+       vkswapchain_images = vku_get_swapchain_images(sc, 0);
+       vk_curr_swapchain_image = vku_get_next_image(vkswapchain);
+}
+
+static void clear(float r, float g, float b)
+{
+}
+
+static void viewport(int x, int y, int width, int height)
+{
+}
+
+static void zbuffer(bool enable)
+{
+}
+
+static void cull_face(Gfx_cull_face cf)
+{
+}
+
+static void swapbuffers()
+{
+}
+
+static void begin_drawing()
+{
+       if((vk_curr_swapchain_image = vku_get_next_image(vkswapchain)) == -1) {
+               fprintf(stderr, "Failed to get swapchain image. Exiting.\n");
+               exit(1);
+       }
+}
+
+static void end_drawing()
+{
+       /* submit queue */
+
+       VkSubmitInfo sinf;
+       memset(&sinf, 0, sizeof sinf);
+       sinf.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+       sinf.waitSemaphoreCount = 1;
+       sinf.pWaitSemaphores = &vk_img_avail_sema;
+       sinf.signalSemaphoreCount = 1;
+       sinf.pSignalSemaphores = &vk_rend_done_sema;
+
+       // the queue should wait on the semaphore
+
+       VkPipelineStageFlags wait_flags = VK_PIPELINE_STAGE_TRANSFER_BIT;
+       sinf.pWaitDstStageMask = &wait_flags;
+       sinf.commandBufferCount = 1;
+       sinf.pCommandBuffers = &swapchain_cmd_bufs[vk_curr_swapchain_image];
+
+       if(vkQueueSubmit(vkq, 1, &sinf, VK_NULL_HANDLE) != VK_SUCCESS) {
+               fprintf(stderr, "Failed to submit drawing command buffer\n");
+               exit(1);
+       }
+
+       /* present drawn image */
+       VkPresentInfoKHR pinf;
+       memset(&pinf, 0, sizeof pinf);
+       pinf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+       pinf.waitSemaphoreCount = 1;
+       pinf.pWaitSemaphores = &vk_rend_done_sema;
+       pinf.swapchainCount = 1;
+       pinf.pSwapchains = &vkswapchain;
+       pinf.pImageIndices = (uint32_t *)&vk_curr_swapchain_image;
+
+       if(vkQueuePresentKHR(vkq, &pinf) != VK_SUCCESS) {
+               fprintf(stderr, "Failed to submit presentation command buffer.\n");
+               exit(1);
+       }
+}
+
+static bool record_cmd_clear(float r, float g, float b)
+{
+       VkCommandBufferBeginInfo binf;
+       binf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+       binf.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+
+       /* this function must be called outside a renderpass instance */
+       const VkClearColorValue pcolor[4] = {r, g, b, 1.0};
+
+       VkImageSubresourceRange range;
+       memset(&range, 0, sizeof range);
+       range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+       range.baseMipLevel = 0;
+       range.baseArrayLayer = 0;
+       range.layerCount = 1;
+
+       for(int i=0; i<vknum_swapchain_images; i++) {
+               /* layout for clearing */
+               VkImageMemoryBarrier cb;
+               memset(&cb, 0, sizeof cb);
+               cb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+               cb.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+               cb.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+               cb.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+               cb.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+               cb.srcQueueFamilyIndex = vkqfamily;
+               cb.dstQueueFamilyIndex = vkqfamily;
+               cb.image = vkswapchain_images[i];
+               cb.subresourceRange = range;
+
+               /* layout for presenting */
+               VkImageMemoryBarrier pb;
+               memset(&pb, 0, sizeof pb);
+               pb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+               pb.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+               pb.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+               pb.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+               pb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+               pb.srcQueueFamilyIndex = vkqfamily;
+               pb.dstQueueFamilyIndex = vkqfamily;
+               pb.image = vkswapchain_images[i];
+               pb.subresourceRange = range;
+
+               vkBeginCommandBuffer(swapchain_cmd_bufs[i], &binf);
+               vkCmdPipelineBarrier(swapchain_cmd_bufs[i], VK_PIPELINE_STAGE_TRANSFER_BIT,
+                                    VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, 0, 0, 1, &pb);
+
+               vkCmdClearColorImage(swapchain_cmd_bufs[i], vkswapchain_images[vk_curr_swapchain_image], VK_IMAGE_LAYOUT_GENERAL,
+                                    pcolor, 1, &range);
+
+               vkCmdPipelineBarrier(swapchain_cmd_bufs[i], VK_PIPELINE_STAGE_TRANSFER_BIT,
+                                    VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &cb);
+
+               if(vkEndCommandBuffer(swapchain_cmd_bufs[i]) != VK_SUCCESS) {
+                       fprintf(stderr, "Failed to record command buffer.\n");
+                       return false;
+               }
+       }
+       return true;
+}
+
+static bool create_swapchain_cmd_bufs(VkCommandPool cpool)
+{
+       swapchain_cmd_bufs = new VkCommandBuffer[vknum_swapchain_images];
+
+       VkCommandBufferAllocateInfo ainf;
+       memset(&ainf, 0, sizeof ainf);
+
+       ainf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+       ainf.commandPool = cpool;
+       ainf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+       ainf.commandBufferCount = (uint32_t)vknum_swapchain_images;
+
+       if(vkAllocateCommandBuffers(vkdev, &ainf, swapchain_cmd_bufs) != VK_SUCCESS) {
+               fprintf(stderr, "Failed to allocate the swapchain command buffers.\n");
+               return false;
+       }
+
+       return true;
 }