1 #define GLFW_INCLUDE_VULKAN
2 #include <GLFW/glfw3.h>
10 #include <gmath/gmath.h>
15 /* global variables */
16 extern GLFWwindow *win;
20 VkCommandBuffer *swapchain_cmd_bufs;
22 /* static functions */
23 static void error_callback(int error, const char *descr);
24 static void clear(float r, float g, float b);
25 static void viewport(int x, int y, int width, int height);
26 static void zbuffer(bool enable);
27 static void cull_face(Gfx_cull_face cf);
28 static void reshape(int width, int height);
29 static void swapbuffers();
30 static void begin_drawing();
31 static void end_drawing();
33 static bool create_swapchain_cmd_bufs(VkCommandPool vkcmdpool);
34 static bool record_cmd_clear(float r, float g, float b);
39 gfx_viewport = viewport;
40 gfx_zbuffer = zbuffer;
41 gfx_cull_face = cull_face;
42 gfx_reshape = reshape;
43 gfx_swapbuffers = swapbuffers;
44 gfx_begin_drawing = begin_drawing;
45 gfx_end_drawing = end_drawing;
48 fprintf(stderr, "Failed to initialize GLFW.\n");
52 if(!glfwVulkanSupported()) {
53 fprintf(stderr, "No Vulkan support on the device.\n");
57 glfwSetErrorCallback(error_callback);
59 if(!vku_create_device()) {
60 fprintf(stderr, "Failed to initialize vulkan.\n");
64 if(!glfwGetPhysicalDevicePresentationSupport(vkinst, vkpdev, vkqfamily)) {
65 fprintf(stderr, "Presentation support not found.\n");
69 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
70 if(!(win = glfwCreateWindow(win_w, win_h, "vkcow", 0, 0))) {
71 fprintf(stderr, "Failed to create window.\n");
75 if(VkResult err = glfwCreateWindowSurface(vkinst, win, 0, &vksurface)) {
76 fprintf(stderr, "Failed to create KHR surface: %s\n", vku_get_vulkan_error_str(err));
80 if(!vku_create_semaphores())
83 if(!(vkswapchain = vku_create_swapchain(vksurface, win_w, win_h, 2,
84 VK_PRESENT_MODE_FIFO_KHR, 0))) {
85 fprintf(stderr, "Failed to create swapchain.\n");
89 vkswapchain_images = vku_get_swapchain_images(vkswapchain, &vknum_swapchain_images);
90 if(!vkswapchain_images) {
91 fprintf(stderr, "Failed to get swapchain images.\n");
95 /* vkswapchain_views = vku_create_image_views(vkswapchain_images, vknum_swapchain_images);
96 if(!vkswapchain_views) {
97 fprintf(stderr, "Failed to create swapchain image views.\n");
98 delete [] vkswapchain_images;
102 if(!create_swapchain_cmd_bufs(vkcmdpool)) {
106 if(!record_cmd_clear(1.0, 0.1, 0.1))
112 void cleanup_vulkan()
114 vkFreeCommandBuffers(vkdev, vkcmdpool, vknum_swapchain_images, swapchain_cmd_bufs);
116 glfwDestroyWindow(win);
120 //TODOs according to the book:
121 // 1- make sure all threads have been terminated (when I add threads)
125 static void error_callback(int error, const char *description)
127 fprintf(stderr, "GLFW error %d: %s.\n", error, description);
130 static void reshape(int width, int height)
133 if(!(sc = vku_create_swapchain(vksurface, width, height, 2, VK_PRESENT_MODE_FIFO_KHR,
135 fprintf(stderr, "Failed to create %dx%d double-buffered swapchain\n", width, height);
140 delete [] vkswapchain_images;
141 vkswapchain_images = vku_get_swapchain_images(sc, 0);
142 vk_curr_swapchain_image = vku_get_next_image(vkswapchain);
145 static void clear(float r, float g, float b)
149 static void viewport(int x, int y, int width, int height)
153 static void zbuffer(bool enable)
157 static void cull_face(Gfx_cull_face cf)
161 static void swapbuffers()
165 static void begin_drawing()
167 if((vk_curr_swapchain_image = vku_get_next_image(vkswapchain)) == -1) {
168 fprintf(stderr, "Failed to get swapchain image. Exiting.\n");
173 static void end_drawing()
178 memset(&sinf, 0, sizeof sinf);
179 sinf.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
180 sinf.waitSemaphoreCount = 1;
181 sinf.pWaitSemaphores = &vk_img_avail_sema;
182 sinf.signalSemaphoreCount = 1;
183 sinf.pSignalSemaphores = &vk_rend_done_sema;
185 // the queue should wait on the semaphore
187 VkPipelineStageFlags wait_flags = VK_PIPELINE_STAGE_TRANSFER_BIT;
188 sinf.pWaitDstStageMask = &wait_flags;
189 sinf.commandBufferCount = 1;
190 sinf.pCommandBuffers = &swapchain_cmd_bufs[vk_curr_swapchain_image];
192 if(vkQueueSubmit(vkq, 1, &sinf, VK_NULL_HANDLE) != VK_SUCCESS) {
193 fprintf(stderr, "Failed to submit drawing command buffer\n");
197 /* present drawn image */
198 VkPresentInfoKHR pinf;
199 memset(&pinf, 0, sizeof pinf);
200 pinf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
201 pinf.waitSemaphoreCount = 1;
202 pinf.pWaitSemaphores = &vk_rend_done_sema;
203 pinf.swapchainCount = 1;
204 pinf.pSwapchains = &vkswapchain;
205 pinf.pImageIndices = (uint32_t *)&vk_curr_swapchain_image;
207 if(vkQueuePresentKHR(vkq, &pinf) != VK_SUCCESS) {
208 fprintf(stderr, "Failed to submit presentation command buffer.\n");
213 static bool record_cmd_clear(float r, float g, float b)
215 VkCommandBufferBeginInfo binf;
216 binf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
217 binf.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
219 /* this function must be called outside a renderpass instance */
220 const VkClearColorValue pcolor[4] = {r, g, b, 1.0};
222 VkImageSubresourceRange range;
223 memset(&range, 0, sizeof range);
224 range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
225 range.baseMipLevel = 0;
226 range.baseArrayLayer = 0;
227 range.layerCount = 1;
229 for(int i=0; i<vknum_swapchain_images; i++) {
230 /* layout for clearing */
231 VkImageMemoryBarrier cb;
232 memset(&cb, 0, sizeof cb);
233 cb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
234 cb.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
235 cb.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
236 cb.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
237 cb.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
238 cb.srcQueueFamilyIndex = vkqfamily;
239 cb.dstQueueFamilyIndex = vkqfamily;
240 cb.image = vkswapchain_images[i];
241 cb.subresourceRange = range;
243 /* layout for presenting */
244 VkImageMemoryBarrier pb;
245 memset(&pb, 0, sizeof pb);
246 pb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
247 pb.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
248 pb.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
249 pb.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
250 pb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
251 pb.srcQueueFamilyIndex = vkqfamily;
252 pb.dstQueueFamilyIndex = vkqfamily;
253 pb.image = vkswapchain_images[i];
254 pb.subresourceRange = range;
256 vkBeginCommandBuffer(swapchain_cmd_bufs[i], &binf);
257 vkCmdPipelineBarrier(swapchain_cmd_bufs[i], VK_PIPELINE_STAGE_TRANSFER_BIT,
258 VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, 0, 0, 1, &pb);
260 vkCmdClearColorImage(swapchain_cmd_bufs[i], vkswapchain_images[vk_curr_swapchain_image], VK_IMAGE_LAYOUT_GENERAL,
263 vkCmdPipelineBarrier(swapchain_cmd_bufs[i], VK_PIPELINE_STAGE_TRANSFER_BIT,
264 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &cb);
266 if(vkEndCommandBuffer(swapchain_cmd_bufs[i]) != VK_SUCCESS) {
267 fprintf(stderr, "Failed to record command buffer.\n");
274 static bool create_swapchain_cmd_bufs(VkCommandPool cpool)
276 swapchain_cmd_bufs = new VkCommandBuffer[vknum_swapchain_images];
278 VkCommandBufferAllocateInfo ainf;
279 memset(&ainf, 0, sizeof ainf);
281 ainf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
282 ainf.commandPool = cpool;
283 ainf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
284 ainf.commandBufferCount = (uint32_t)vknum_swapchain_images;
286 if(vkAllocateCommandBuffers(vkdev, &ainf, swapchain_cmd_bufs) != VK_SUCCESS) {
287 fprintf(stderr, "Failed to allocate the swapchain command buffers.\n");