1 #define GLFW_INCLUDE_VULKAN
2 #include <GLFW/glfw3.h>
11 #include <gmath/gmath.h>
13 #include "allocator.h"
19 /* global variables */
20 extern GLFWwindow *win;
24 static VkCommandBuffer cmd_buf; // command buffer used at zbuffer creation
27 static VkImageView dview;
29 static VkImage *images;
30 static VkImageView *iviews;
31 static uint32_t num_images;
33 /* static variables */
34 static VkDeviceMemory gpu_mem; // to be replaced when I fix the allocator
35 // zbuffer image, view:
37 VkCommandBuffer *swapchain_cmd_bufs;
39 /* static functions */
40 static void error_callback(int error, const char *descr);
41 static void clear(float r, float g, float b);
42 static void viewport(int x, int y, int width, int height);
43 static void zbuffer(bool enable);
44 static void cull_face(Gfx_cull_face cf);
45 static void reshape(int width, int height);
46 static void swapbuffers();
47 static void begin_drawing();
48 static void end_drawing();
50 static bool create_swapchain();
51 static bool begin_command_buffer();
52 static bool create_swapchain_image_views(VkFormat format);
53 static bool create_zbuffer();
55 static bool create_swapchain_cmd_bufs(VkCommandPool vk_pool);
56 static bool record_cmd_clear(float r, float g, float b);
61 fprintf(stderr, "Failed to initialize GLFW.\n");
65 if(!glfwVulkanSupported()) {
66 fprintf(stderr, "No Vulkan support on the device.\n");
71 glfwSetErrorCallback(error_callback);
73 /* create device and command pool! */
74 if(!vku_create_device()) {
75 fprintf(stderr, "Failed to initialize vulkan.\n");
79 if(!glfwGetPhysicalDevicePresentationSupport(vkinst, vk_physical, vkqfamily)) {
80 fprintf(stderr, "Presentation support not found.\n");
84 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
85 if(!(win = glfwCreateWindow(win_w, win_h, "vkcow", 0, 0))) {
86 fprintf(stderr, "Failed to create window.\n");
90 VkResult res = glfwCreateWindowSurface(vkinst, win, 0, &vk_surface);
91 if(res != VK_SUCCESS) {
92 fprintf(stderr, "Failed to create KHR surface: %s\n", vku_get_vulkan_error_str(res));
96 if(!create_swapchain()) {
97 fprintf(stderr, "Failed to create swapchain.\n");
101 cmd_buf = VK_NULL_HANDLE;
102 if(!begin_command_buffer()) {
103 fprintf(stderr, "Failed to start VK_NULL_HANDLE command buffer.\n");
107 if(!create_zbuffer()) {
108 fprintf(stderr, "Failed to create depth buffer.\n");
113 gfx_viewport = viewport;
114 gfx_zbuffer = zbuffer;
115 gfx_cull_face = cull_face;
116 gfx_reshape = reshape;
117 gfx_swapbuffers = swapbuffers;
118 gfx_begin_drawing = begin_drawing;
119 gfx_end_drawing = end_drawing;
123 if(!vku_create_semaphores())
126 if(!(vk_swapchain = vku_create_swapchain(vk_surface, win_w, win_h, 2,
127 VK_PRESENT_MODE_IMMEDIATE_KHR, 0))) {
128 fprintf(stderr, "Failed to create swapchain.\n");
132 vkswapchain_images = vku_get_swapchain_images(vk_swapchain, &vknum_swapchain_images);
133 if(!vkswapchain_images) {
134 fprintf(stderr, "Failed to get swapchain images.\n");
138 // vkswapchain_views = vku_create_image_views(vkswapchain_images, vknum_swapchain_images);
139 // if(!vkswapchain_views) {
140 // fprintf(stderr, "Failed to create swapchain image views.\n");
141 // delete [] vkswapchain_images;
145 if(!create_swapchain_cmd_bufs(vk_pool)) {
149 if(!record_cmd_clear(1.0, 0.1, 0.1))
156 static bool create_swapchain()
158 /* surface capabilities */
159 VkSurfaceCapabilitiesKHR scap;
160 if(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical, vk_surface, &scap) != VK_SUCCESS) {
161 fprintf(stderr, "Failed to get physical device surface capabilities\n");
165 /* presentation modes */
167 if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, 0) != VK_SUCCESS) {
168 fprintf(stderr, "Failed to get physical device surface presentation modes count.\n");
172 if(prmode_cnt == 0) {
173 fprintf(stderr, "Presentation modes not found.\n");
177 VkPresentModeKHR scmode = VK_PRESENT_MODE_FIFO_KHR;
178 VkPresentModeKHR *modes = new VkPresentModeKHR[prmode_cnt];
180 if(vkGetPhysicalDeviceSurfacePresentModesKHR(vk_physical, vk_surface, &prmode_cnt, modes) != VK_SUCCESS) {
181 fprintf(stderr, "Failed to get physical device presentation modes.\n");
185 for(uint32_t i=0; i<prmode_cnt; i++) {
186 if(modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
187 scmode = VK_PRESENT_MODE_MAILBOX_KHR;
190 if((scmode != VK_PRESENT_MODE_MAILBOX_KHR) && (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) {
192 scmode = VK_PRESENT_MODE_IMMEDIATE_KHR;
196 /* swapchain extents */
198 if(scap.currentExtent.width == 0xffffffff || scap.currentExtent.height == 0xffffffff) {
199 scextent.width = win_w;
200 scextent.height = win_h;
203 scextent = scap.currentExtent;
204 win_w = scextent.width;
205 win_h = scextent.height;
208 /* number of swapchain images (on intel that's 3: maybe should hardcode it to 2?) */
209 num_images = scap.minImageCount; //+ 1;
210 /* intel doesn't set the maxImageCount */
211 if(scap.maxImageCount > 0 && num_images > scap.maxImageCount)
212 num_images = scap.maxImageCount;
214 printf("num_images : %u\n", num_images);
215 assert(num_images > 0);
217 /* transform flags */
218 VkSurfaceTransformFlagBitsKHR pre_transf = scap.currentTransform;
219 if(scap.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
220 pre_transf = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
222 /* find suitable colorspace, format */
224 if(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical, vk_surface, &fcount, 0) != VK_SUCCESS) {
225 fprintf(stderr, "Failed to get format count for physical device.\n");
229 fprintf(stderr, "No color formats were found.\n");
234 VkColorSpaceKHR colorspace;
236 VkSurfaceFormatKHR *formats = new VkSurfaceFormatKHR[fcount];
237 if(vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical, vk_surface, &fcount, formats) != VK_SUCCESS) {
238 fprintf(stderr, "Failed to get surface formats.\n");
241 if((fcount == 1) && (formats[0].format == VK_FORMAT_UNDEFINED)) {
242 format = VK_FORMAT_B8G8R8_UNORM;
244 format = formats[0].format;
246 colorspace = formats[0].colorSpace;
248 /* creating the swapchain */
249 VkSwapchainCreateInfoKHR sinfo;
250 memset(&sinfo, 0, sizeof sinfo);
252 sinfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
253 sinfo.surface = vk_surface;
254 sinfo.minImageCount = num_images;
255 sinfo.imageFormat = format;
256 sinfo.imageColorSpace = colorspace;
257 sinfo.imageExtent = scextent;
258 sinfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
259 sinfo.preTransform = pre_transf;
260 sinfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
261 sinfo.imageArrayLayers = 1;
262 sinfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
263 sinfo.presentMode = scmode;
264 sinfo.oldSwapchain = VK_NULL_HANDLE; //TODO
265 sinfo.clipped = VK_TRUE; //TODO
267 if(vkCreateSwapchainKHR(vk_device, &sinfo, 0, &vk_swapchain) != VK_SUCCESS) {
268 fprintf(stderr, "Failed to create swapchain.\n");
272 if(vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &num_images, 0) != VK_SUCCESS) {
273 fprintf(stderr, "Failed to get the number of the swapchain images.\n");
277 images = new VkImage[num_images];
278 if(vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &num_images, images) != VK_SUCCESS) {
279 fprintf(stderr, "Failed to get the swapchain images.\n");
284 if(!create_swapchain_image_views(format)) {
285 fprintf(stderr, "Failed to create image views for the swapchain images.\n");
295 static bool create_swapchain_image_views(VkFormat format)
297 VkImageViewCreateInfo ivinf;
298 memset(&ivinf, 0, sizeof ivinf);
300 ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
301 ivinf.format = format;
303 VK_COMPONENT_SWIZZLE_R,
304 VK_COMPONENT_SWIZZLE_G,
305 VK_COMPONENT_SWIZZLE_B,
306 VK_COMPONENT_SWIZZLE_A
308 ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
309 ivinf.subresourceRange.levelCount = 1;
310 ivinf.subresourceRange.layerCount = 1;
311 ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
313 iviews = new VkImageView[num_images];
314 for(uint32_t i=0; i<num_images; i++) {
315 ivinf.image = images[i];
316 if(vkCreateImageView(vk_device, &ivinf, 0, &iviews[i]) != VK_SUCCESS) {
317 fprintf(stderr, "Failed to create view for the swapchain image: %d.\n", i);
324 static bool begin_command_buffer()
326 if(cmd_buf == VK_NULL_HANDLE) {
327 cmd_buf = vku_alloc_cmdbuf(vk_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
329 VkCommandBufferInheritanceInfo ciinf;
330 memset(&ciinf, 0, sizeof ciinf);
331 ciinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
332 ciinf.renderPass = VK_NULL_HANDLE;
333 ciinf.framebuffer = VK_NULL_HANDLE;
334 ciinf.occlusionQueryEnable = VK_FALSE;
336 VkCommandBufferBeginInfo cbinf;
337 memset(&cbinf, 0, sizeof cbinf);
338 cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
339 cbinf.pInheritanceInfo = &ciinf;
341 if(vkBeginCommandBuffer(cmd_buf, &cbinf) != VK_SUCCESS) {
342 fprintf(stderr, "Failed to begin command buffer.\n");
349 static bool create_zbuffer()
351 VkFormat dformat = VK_FORMAT_D32_SFLOAT_S8_UINT;
353 VkImageCreateInfo dinfo;
354 memset(&dinfo, 0, sizeof dinfo);
356 dinfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
357 dinfo.imageType = VK_IMAGE_TYPE_2D;
358 dinfo.format = dformat;
359 dinfo.extent = {win_w, win_h, 1};
361 dinfo.arrayLayers = 1;
362 dinfo.samples = VK_SAMPLE_COUNT_1_BIT;
363 dinfo.tiling = VK_IMAGE_TILING_OPTIMAL;
364 dinfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
366 if(vkCreateImage(vk_device, &dinfo, 0, &dimg) != VK_SUCCESS) {
367 fprintf(stderr, "Failed to create depth buffer image.\n");
371 VkMemoryRequirements dmem_reqs;
372 vkGetImageMemoryRequirements(vk_device, dimg, &dmem_reqs);
374 gpu_mem = vk_allocate(dmem_reqs.size);
379 vkBindImageMemory(vk_device, dimg, gpu_mem, 0);
381 // XXX set image layout
382 if(!vk_image_set_layout(cmd_buf, dimg, VK_IMAGE_ASPECT_DEPTH_BIT,
383 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
384 (VkAccessFlagBits)0)) {
385 fprintf(stderr, "Failed to set depth buffer layout.\n");
389 VkImageViewCreateInfo div_inf;
390 memset(&div_inf, 0, sizeof div_inf);
392 div_inf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
393 div_inf.image = dimg;
394 div_inf.format = dformat;
395 div_inf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
396 div_inf.subresourceRange.levelCount = 1;
397 div_inf.subresourceRange.layerCount = 1;
398 div_inf.viewType = VK_IMAGE_VIEW_TYPE_2D;
400 if(vkCreateImageView(vk_device, &div_inf, 0, &dview) != VK_SUCCESS) {
401 fprintf(stderr, "Failed to create image view for depth buffer.\n");
407 void cleanup_vulkan()
409 vkFreeCommandBuffers(vk_device, vk_pool, vknum_swapchain_images, swapchain_cmd_bufs);
411 glfwDestroyWindow(win);
415 //TODOs according to the book:
416 // 1- make sure all threads have been terminated (when I add threads)
420 static void error_callback(int error, const char *description)
422 fprintf(stderr, "GLFW error %d: %s.\n", error, description);
425 static void reshape(int width, int height)
428 if(!(sc = vku_create_swapchain(vk_surface, width, height, 2, VK_PRESENT_MODE_FIFO_KHR,
430 fprintf(stderr, "Failed to create %dx%d double-buffered swapchain\n", width, height);
435 delete [] vkswapchain_images;
436 vkswapchain_images = vku_get_swapchain_images(sc, 0);
437 vk_curr_swapchain_image = vku_get_next_image(vk_swapchain);
440 static void clear(float r, float g, float b)
444 static void viewport(int x, int y, int width, int height)
448 static void zbuffer(bool enable)
452 static void cull_face(Gfx_cull_face cf)
456 static void swapbuffers()
460 static void begin_drawing()
462 // if((vk_curr_swapchain_image = vku_get_next_image(vk_swapchain)) == -1) {
463 // fprintf(stderr, "Failed to get swapchain image. Exiting.\n");
468 static void end_drawing()
472 // VkSubmitInfo sinf;
473 // memset(&sinf, 0, sizeof sinf);
474 // sinf.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
475 // sinf.waitSemaphoreCount = 1;
476 // sinf.pWaitSemaphores = &vk_img_avail_sema;
477 // sinf.signalSemaphoreCount = 1;
478 // sinf.pSignalSemaphores = &vk_rend_done_sema;
480 // // the queue should wait on the semaphore
482 // VkPipelineStageFlags wait_flags = VK_PIPELINE_STAGE_TRANSFER_BIT;
483 // sinf.pWaitDstStageMask = &wait_flags;
484 // sinf.commandBufferCount = 1;
485 // sinf.pCommandBuffers = &swapchain_cmd_bufs[vk_curr_swapchain_image];
487 // if(vkQueueSubmit(vk_queue, 1, &sinf, VK_NULL_HANDLE) != VK_SUCCESS) {
488 // fprintf(stderr, "Failed to submit drawing command buffer\n");
492 // /* present drawn image */
493 // VkPresentInfoKHR pinf;
494 // memset(&pinf, 0, sizeof pinf);
495 // pinf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
496 // pinf.waitSemaphoreCount = 1;
497 // pinf.pWaitSemaphores = &vk_rend_done_sema;
498 // pinf.swapchainCount = 1;
499 // pinf.pSwapchains = &vk_swapchain;
500 // pinf.pImageIndices = (uint32_t *)&vk_curr_swapchain_image;
502 // if(vkQueuePresentKHR(vk_queue, &pinf) != VK_SUCCESS) {
503 // fprintf(stderr, "Failed to submit presentation command buffer.\n");
508 static bool record_cmd_clear(float r, float g, float b)
510 // VkCommandBufferBeginInfo binf;
511 // binf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
512 // binf.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
514 // /* this function must be called outside a renderpass instance */
515 // const VkClearColorValue pcolor[4] = {r, g, b, 1.0};
517 // VkImageSubresourceRange range;
518 // memset(&range, 0, sizeof range);
519 // range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
520 // range.baseMipLevel = 0;
521 // range.baseArrayLayer = 0;
522 // range.layerCount = 1;
524 // for(int i=0; i<vknum_swapchain_images; i++) {
525 // /* layout for clearing */
526 // VkImageMemoryBarrier cb;
527 // memset(&cb, 0, sizeof cb);
528 // cb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
529 // cb.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
530 // cb.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
531 // cb.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
532 // cb.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
533 // cb.srcQueueFamilyIndex = vkqfamily;
534 // cb.dstQueueFamilyIndex = vkqfamily;
535 // cb.image = vkswapchain_images[i];
536 // cb.subresourceRange = range;
538 // /* layout for presenting */
539 // VkImageMemoryBarrier pb;
540 // memset(&pb, 0, sizeof pb);
541 // pb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
542 // pb.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
543 // pb.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
544 // pb.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
545 // pb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
546 // pb.srcQueueFamilyIndex = vkqfamily;
547 // pb.dstQueueFamilyIndex = vkqfamily;
548 // pb.image = vkswapchain_images[i];
549 // pb.subresourceRange = range;
551 // vkBeginCommandBuffer(swapchain_cmd_bufs[i], &binf);
552 // vkCmdPipelineBarrier(swapchain_cmd_bufs[i], VK_PIPELINE_STAGE_TRANSFER_BIT,
553 // VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, 0, 0, 1, &pb);
555 // vkCmdClearColorImage(swapchain_cmd_bufs[i], vkswapchain_images[vk_curr_swapchain_image], VK_IMAGE_LAYOUT_GENERAL,
556 // pcolor, 1, &range);
558 // vkCmdPipelineBarrier(swapchain_cmd_bufs[i], VK_PIPELINE_STAGE_TRANSFER_BIT,
559 // VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &cb);
561 // if(vkEndCommandBuffer(swapchain_cmd_bufs[i]) != VK_SUCCESS) {
562 // fprintf(stderr, "Failed to record command buffer.\n");
569 // static bool create_swapchain_cmd_bufs(VkCommandPool cpool)
571 // swapchain_cmd_bufs = new VkCommandBuffer[vknum_swapchain_images];
573 // VkCommandBufferAllocateInfo ainf;
574 // memset(&ainf, 0, sizeof ainf);
576 // ainf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
577 // ainf.commandPool = cpool;
578 // ainf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
579 // ainf.commandBufferCount = (uint32_t)vknum_swapchain_images;
581 // if(vkAllocateCommandBuffers(vk_device, &ainf, swapchain_cmd_bufs) != VK_SUCCESS) {
582 // fprintf(stderr, "Failed to allocate the swapchain command buffers.\n");