backup - needs fixing
[demo] / src / vulkan / vk.cc
1 #define GLFW_INCLUDE_VULKAN
2 #include <GLFW/glfw3.h>
3
4 #include <alloca.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <string>
8 #include <vector>
9
10 #include <gmath/gmath.h>
11
12 #include "gfxapi.h"
13 #include "vkutil.h"
14
15 /* global variables */
16 extern GLFWwindow *win;
17 extern int win_w;
18 extern int win_h;
19
20 VkCommandBuffer *swapchain_cmd_bufs;
21
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();
32
33 static bool create_swapchain_cmd_bufs(VkCommandPool vkcmdpool);
34 static bool record_cmd_clear(float r, float g, float b);
35
36 bool init_vulkan()
37 {
38         gfx_clear = clear;
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;
46
47         if(!glfwInit()) {
48                 fprintf(stderr, "Failed to initialize GLFW.\n");
49                 return false;
50         }
51
52         if(!glfwVulkanSupported()) {
53                 fprintf(stderr, "No Vulkan support on the device.\n");
54                 return false;
55         }
56
57         glfwSetErrorCallback(error_callback);
58
59         if(!vku_create_device()) {
60                 fprintf(stderr, "Failed to initialize vulkan.\n");
61                 return false;
62         }
63
64         if(!glfwGetPhysicalDevicePresentationSupport(vkinst, vkpdev, vkqfamily)) {
65                 fprintf(stderr, "Presentation support not found.\n");
66                 return false;
67         }
68
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");
72                 return false;
73         }
74
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));
77                 return false;
78         }
79
80         if(!vku_create_semaphores())
81                 return false;
82
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");
86                 return false;
87         }
88
89         vkswapchain_images = vku_get_swapchain_images(vkswapchain, &vknum_swapchain_images);
90         if(!vkswapchain_images) {
91                 fprintf(stderr, "Failed to get swapchain images.\n");
92                 return false;
93         }
94
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;
99                         return false;
100                 }
101         */
102         if(!create_swapchain_cmd_bufs(vkcmdpool)) {
103                 return false;
104         }
105
106         if(!record_cmd_clear(1.0, 0.1, 0.1))
107                 return false;
108
109         return true;
110 }
111
112 void cleanup_vulkan()
113 {
114         vkFreeCommandBuffers(vkdev, vkcmdpool, vknum_swapchain_images, swapchain_cmd_bufs);
115         if(win) {
116                 glfwDestroyWindow(win);
117         }
118         glfwTerminate();
119
120         //TODOs according to the book:
121         // 1- make sure all threads have been terminated (when I add threads)
122         vku_cleanup();
123 }
124
125 static void error_callback(int error, const char *description)
126 {
127         fprintf(stderr, "GLFW error %d: %s.\n", error, description);
128 }
129
130 static void reshape(int width, int height)
131 {
132         VkSwapchainKHR sc;
133         if(!(sc = vku_create_swapchain(vksurface, width, height, 2, VK_PRESENT_MODE_FIFO_KHR,
134                                        vkswapchain))) {
135                 fprintf(stderr, "Failed to create %dx%d double-buffered swapchain\n", width, height);
136                 return;
137         }
138         vkswapchain = sc;
139
140         delete [] vkswapchain_images;
141         vkswapchain_images = vku_get_swapchain_images(sc, 0);
142         vk_curr_swapchain_image = vku_get_next_image(vkswapchain);
143 }
144
145 static void clear(float r, float g, float b)
146 {
147 }
148
149 static void viewport(int x, int y, int width, int height)
150 {
151 }
152
153 static void zbuffer(bool enable)
154 {
155 }
156
157 static void cull_face(Gfx_cull_face cf)
158 {
159 }
160
161 static void swapbuffers()
162 {
163 }
164
165 static void begin_drawing()
166 {
167         if((vk_curr_swapchain_image = vku_get_next_image(vkswapchain)) == -1) {
168                 fprintf(stderr, "Failed to get swapchain image. Exiting.\n");
169                 exit(1);
170         }
171 }
172
173 static void end_drawing()
174 {
175         /* submit queue */
176
177         VkSubmitInfo sinf;
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;
184
185         // the queue should wait on the semaphore
186
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];
191
192         if(vkQueueSubmit(vkq, 1, &sinf, VK_NULL_HANDLE) != VK_SUCCESS) {
193                 fprintf(stderr, "Failed to submit drawing command buffer\n");
194                 exit(1);
195         }
196
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;
206
207         if(vkQueuePresentKHR(vkq, &pinf) != VK_SUCCESS) {
208                 fprintf(stderr, "Failed to submit presentation command buffer.\n");
209                 exit(1);
210         }
211 }
212
213 static bool record_cmd_clear(float r, float g, float b)
214 {
215         VkCommandBufferBeginInfo binf;
216         binf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
217         binf.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
218
219         /* this function must be called outside a renderpass instance */
220         const VkClearColorValue pcolor[4] = {r, g, b, 1.0};
221
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;
228
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;
242
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;
255
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);
259
260                 vkCmdClearColorImage(swapchain_cmd_bufs[i], vkswapchain_images[vk_curr_swapchain_image], VK_IMAGE_LAYOUT_GENERAL,
261                                      pcolor, 1, &range);
262
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);
265
266                 if(vkEndCommandBuffer(swapchain_cmd_bufs[i]) != VK_SUCCESS) {
267                         fprintf(stderr, "Failed to record command buffer.\n");
268                         return false;
269                 }
270         }
271         return true;
272 }
273
274 static bool create_swapchain_cmd_bufs(VkCommandPool cpool)
275 {
276         swapchain_cmd_bufs = new VkCommandBuffer[vknum_swapchain_images];
277
278         VkCommandBufferAllocateInfo ainf;
279         memset(&ainf, 0, sizeof ainf);
280
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;
285
286         if(vkAllocateCommandBuffers(vkdev, &ainf, swapchain_cmd_bufs) != VK_SUCCESS) {
287                 fprintf(stderr, "Failed to allocate the swapchain command buffers.\n");
288                 return false;
289         }
290
291         return true;
292 }