• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2015-2016 The Khronos Group Inc.
3 * Copyright (c) 2015-2016 Valve Corporation
4 * Copyright (c) 2015-2016 LunarG, Inc.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Author: Jeremy Hayes <jeremy@lunarg.com>
19 */
20 
21 #if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
22 #include <X11/Xutil.h>
23 #endif
24 
25 #include <cassert>
26 #include <cstdio>
27 #include <cstdlib>
28 #include <cstring>
29 #include <csignal>
30 #include <memory>
31 
32 #define VULKAN_HPP_NO_EXCEPTIONS
33 #include <vulkan/vulkan.hpp>
34 #include <vulkan/vk_sdk_platform.h>
35 
36 #include "linmath.h"
37 
38 #ifndef NDEBUG
39 #define VERIFY(x) assert(x)
40 #else
41 #define VERIFY(x) ((void)(x))
42 #endif
43 
44 #define APP_SHORT_NAME "cube"
45 #ifdef _WIN32
46 #define APP_NAME_STR_LEN 80
47 #endif
48 
49 // Allow a maximum of two outstanding presentation operations.
50 #define FRAME_LAG 2
51 
52 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
53 
54 #ifdef _WIN32
55 #define ERR_EXIT(err_msg, err_class)                                           \
56     do {                                                                       \
57         if (!suppress_popups)                                                  \
58             MessageBox(nullptr, err_msg, err_class, MB_OK);                    \
59         exit(1);                                                               \
60     } while (0)
61 #else
62 #define ERR_EXIT(err_msg, err_class)                                           \
63     do {                                                                       \
64         printf(err_msg);                                                       \
65         fflush(stdout);                                                        \
66         exit(1);                                                               \
67     } while (0)
68 #endif
69 
70 struct texture_object {
71     vk::Sampler sampler;
72 
73     vk::Image image;
74     vk::ImageLayout imageLayout;
75 
76     vk::MemoryAllocateInfo mem_alloc;
77     vk::DeviceMemory mem;
78     vk::ImageView view;
79 
80     int32_t tex_width;
81     int32_t tex_height;
82 };
83 
84 static char const *const tex_files[] = {"lunarg.ppm"};
85 
86 static int validation_error = 0;
87 
88 struct vkcube_vs_uniform {
89     // Must start with MVP
90     float mvp[4][4];
91     float position[12 * 3][4];
92     float color[12 * 3][4];
93 };
94 
95 struct vktexcube_vs_uniform {
96     // Must start with MVP
97     float mvp[4][4];
98     float position[12 * 3][4];
99     float attr[12 * 3][4];
100 };
101 
102 //--------------------------------------------------------------------------------------
103 // Mesh and VertexFormat Data
104 //--------------------------------------------------------------------------------------
105 // clang-format off
106 static const float g_vertex_buffer_data[] = {
107     -1.0f,-1.0f,-1.0f,  // -X side
108     -1.0f,-1.0f, 1.0f,
109     -1.0f, 1.0f, 1.0f,
110     -1.0f, 1.0f, 1.0f,
111     -1.0f, 1.0f,-1.0f,
112     -1.0f,-1.0f,-1.0f,
113 
114     -1.0f,-1.0f,-1.0f,  // -Z side
115      1.0f, 1.0f,-1.0f,
116      1.0f,-1.0f,-1.0f,
117     -1.0f,-1.0f,-1.0f,
118     -1.0f, 1.0f,-1.0f,
119      1.0f, 1.0f,-1.0f,
120 
121     -1.0f,-1.0f,-1.0f,  // -Y side
122      1.0f,-1.0f,-1.0f,
123      1.0f,-1.0f, 1.0f,
124     -1.0f,-1.0f,-1.0f,
125      1.0f,-1.0f, 1.0f,
126     -1.0f,-1.0f, 1.0f,
127 
128     -1.0f, 1.0f,-1.0f,  // +Y side
129     -1.0f, 1.0f, 1.0f,
130      1.0f, 1.0f, 1.0f,
131     -1.0f, 1.0f,-1.0f,
132      1.0f, 1.0f, 1.0f,
133      1.0f, 1.0f,-1.0f,
134 
135      1.0f, 1.0f,-1.0f,  // +X side
136      1.0f, 1.0f, 1.0f,
137      1.0f,-1.0f, 1.0f,
138      1.0f,-1.0f, 1.0f,
139      1.0f,-1.0f,-1.0f,
140      1.0f, 1.0f,-1.0f,
141 
142     -1.0f, 1.0f, 1.0f,  // +Z side
143     -1.0f,-1.0f, 1.0f,
144      1.0f, 1.0f, 1.0f,
145     -1.0f,-1.0f, 1.0f,
146      1.0f,-1.0f, 1.0f,
147      1.0f, 1.0f, 1.0f,
148 };
149 
150 static const float g_uv_buffer_data[] = {
151     0.0f, 1.0f,  // -X side
152     1.0f, 1.0f,
153     1.0f, 0.0f,
154     1.0f, 0.0f,
155     0.0f, 0.0f,
156     0.0f, 1.0f,
157 
158     1.0f, 1.0f,  // -Z side
159     0.0f, 0.0f,
160     0.0f, 1.0f,
161     1.0f, 1.0f,
162     1.0f, 0.0f,
163     0.0f, 0.0f,
164 
165     1.0f, 0.0f,  // -Y side
166     1.0f, 1.0f,
167     0.0f, 1.0f,
168     1.0f, 0.0f,
169     0.0f, 1.0f,
170     0.0f, 0.0f,
171 
172     1.0f, 0.0f,  // +Y side
173     0.0f, 0.0f,
174     0.0f, 1.0f,
175     1.0f, 0.0f,
176     0.0f, 1.0f,
177     1.0f, 1.0f,
178 
179     1.0f, 0.0f,  // +X side
180     0.0f, 0.0f,
181     0.0f, 1.0f,
182     0.0f, 1.0f,
183     1.0f, 1.0f,
184     1.0f, 0.0f,
185 
186     0.0f, 0.0f,  // +Z side
187     0.0f, 1.0f,
188     1.0f, 0.0f,
189     0.0f, 1.0f,
190     1.0f, 1.0f,
191     1.0f, 0.0f,
192 };
193 // clang-format on
194 
195 typedef struct {
196     vk::Image image;
197     vk::CommandBuffer cmd;
198     vk::CommandBuffer graphics_to_present_cmd;
199     vk::ImageView view;
200 } SwapchainBuffers;
201 
202 #ifdef _WIN32
203 // MS-Windows event handling function:
204 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
205 #endif
206 
207 struct Demo {
DemoDemo208     Demo()
209         :
210 #if defined(VK_USE_PLATFORM_WIN32_KHR)
211           connection{nullptr},
212           window{nullptr},
213           minsize(POINT{
214               0, 0}), // Use explicit construction to avoid MSVC error C2797.
215 #elif defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
216           display{nullptr},
217           xlib_window{0}, xlib_wm_delete_window{0}, connection{nullptr},
218           screen{nullptr}, xcb_window{0}, atom_wm_delete_window{nullptr},
219 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
220           display{nullptr},
221           registry{nullptr}, compositor{nullptr}, window{nullptr},
222           shell{nullptr}, shell_surface{nullptr},
223 #endif
224           prepared{false},
225           use_staging_buffer{false}, use_xlib{false},
226           graphics_queue_family_index{0}, present_queue_family_index{0},
227           enabled_extension_count{0}, enabled_layer_count{0}, width{0},
228           height{0}, swapchainImageCount{0}, frame_index{0}, spin_angle{0.0f},
229           spin_increment{0.0f}, pause{false}, quit{false}, curFrame{0},
230           frameCount{0}, validate{false}, use_break{false},
231           suppress_popups{false}, current_buffer{0}, queue_family_count{0} {
232 #if defined(VK_USE_PLATFORM_WIN32_KHR)
233         memset(name, '\0', APP_NAME_STR_LEN);
234 #elif defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
235 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
236 #endif
237         memset(fencesInited, 0, sizeof(bool) * FRAME_LAG);
238         memset(projection_matrix, 0, sizeof(projection_matrix));
239         memset(view_matrix, 0, sizeof(view_matrix));
240         memset(model_matrix, 0, sizeof(model_matrix));
241     }
242 
build_image_ownership_cmdDemo243     void build_image_ownership_cmd(uint32_t const &i) {
244         auto const cmd_buf_info = vk::CommandBufferBeginInfo().setFlags(
245             vk::CommandBufferUsageFlagBits::eSimultaneousUse);
246         auto result = buffers[i].graphics_to_present_cmd.begin(&cmd_buf_info);
247         VERIFY(result == vk::Result::eSuccess);
248 
249         auto const image_ownership_barrier =
250             vk::ImageMemoryBarrier()
251                 .setSrcAccessMask(vk::AccessFlags())
252                 .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
253                 .setOldLayout(vk::ImageLayout::ePresentSrcKHR)
254                 .setNewLayout(vk::ImageLayout::ePresentSrcKHR)
255                 .setSrcQueueFamilyIndex(graphics_queue_family_index)
256                 .setDstQueueFamilyIndex(present_queue_family_index)
257                 .setImage(buffers[i].image)
258                 .setSubresourceRange(vk::ImageSubresourceRange(
259                     vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
260 
261         buffers[i].graphics_to_present_cmd.pipelineBarrier(
262             vk::PipelineStageFlagBits::eColorAttachmentOutput,
263             vk::PipelineStageFlagBits::eColorAttachmentOutput,
264             vk::DependencyFlagBits(), 0, nullptr, 0, nullptr, 1,
265             &image_ownership_barrier);
266 
267         result = buffers[i].graphics_to_present_cmd.end();
268         VERIFY(result == vk::Result::eSuccess);
269     }
270 
check_layersDemo271     vk::Bool32 check_layers(uint32_t check_count,
272                             char const *const *const check_names,
273                             uint32_t layer_count, vk::LayerProperties *layers) {
274         for (uint32_t i = 0; i < check_count; i++) {
275             vk::Bool32 found = VK_FALSE;
276             for (uint32_t j = 0; j < layer_count; j++) {
277                 if (!strcmp(check_names[i], layers[j].layerName)) {
278                     found = VK_TRUE;
279                     break;
280                 }
281             }
282             if (!found) {
283                 fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
284                 return 0;
285             }
286         }
287         return VK_TRUE;
288     }
289 
cleanupDemo290     void cleanup() {
291         prepared = false;
292         device.waitIdle();
293 
294         // Wait for fences from present operations
295         for (uint32_t i = 0; i < FRAME_LAG; i++) {
296             if (fencesInited[i]) {
297                 device.waitForFences(1, &fences[i], VK_TRUE, UINT64_MAX);
298             }
299             device.destroyFence(fences[i], nullptr);
300             device.destroySemaphore(image_acquired_semaphores[i], nullptr);
301             device.destroySemaphore(draw_complete_semaphores[i], nullptr);
302             if (separate_present_queue) {
303                 device.destroySemaphore(image_ownership_semaphores[i], nullptr);
304             }
305         }
306 
307         for (uint32_t i = 0; i < swapchainImageCount; i++) {
308             device.destroyFramebuffer(framebuffers[i], nullptr);
309         }
310         device.destroyDescriptorPool(desc_pool, nullptr);
311 
312         device.destroyPipeline(pipeline, nullptr);
313         device.destroyPipelineCache(pipelineCache, nullptr);
314         device.destroyRenderPass(render_pass, nullptr);
315         device.destroyPipelineLayout(pipeline_layout, nullptr);
316         device.destroyDescriptorSetLayout(desc_layout, nullptr);
317 
318         for (uint32_t i = 0; i < texture_count; i++) {
319             device.destroyImageView(textures[i].view, nullptr);
320             device.destroyImage(textures[i].image, nullptr);
321             device.freeMemory(textures[i].mem, nullptr);
322             device.destroySampler(textures[i].sampler, nullptr);
323         }
324         device.destroySwapchainKHR(swapchain, nullptr);
325 
326         device.destroyImageView(depth.view, nullptr);
327         device.destroyImage(depth.image, nullptr);
328         device.freeMemory(depth.mem, nullptr);
329 
330         device.destroyBuffer(uniform_data.buf, nullptr);
331         device.freeMemory(uniform_data.mem, nullptr);
332 
333         for (uint32_t i = 0; i < swapchainImageCount; i++) {
334             device.destroyImageView(buffers[i].view, nullptr);
335             device.freeCommandBuffers(cmd_pool, 1, &buffers[i].cmd);
336         }
337 
338         device.destroyCommandPool(cmd_pool, nullptr);
339 
340         if (separate_present_queue) {
341             device.destroyCommandPool(present_cmd_pool, nullptr);
342         }
343 
344         device.destroy(nullptr);
345         inst.destroySurfaceKHR(surface, nullptr);
346         inst.destroy(nullptr);
347 
348 #if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
349         if (use_xlib) {
350             XDestroyWindow(display, xlib_window);
351             XCloseDisplay(display);
352         } else {
353             xcb_destroy_window(connection, xcb_window);
354             xcb_disconnect(connection);
355         }
356         free(atom_wm_delete_window);
357 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
358         wl_shell_surface_destroy(shell_surface);
359         wl_surface_destroy(window);
360         wl_shell_destroy(shell);
361         wl_compositor_destroy(compositor);
362         wl_registry_destroy(registry);
363         wl_display_disconnect(display);
364 #endif
365     }
366 
create_deviceDemo367     void create_device() {
368         float const priorities[1] = {0.0};
369 
370         vk::DeviceQueueCreateInfo queues[2];
371         queues[0].setQueueFamilyIndex(graphics_queue_family_index);
372         queues[0].setQueueCount(1);
373         queues[0].setPQueuePriorities(priorities);
374 
375         auto deviceInfo = vk::DeviceCreateInfo()
376                               .setQueueCreateInfoCount(1)
377                               .setPQueueCreateInfos(queues)
378                               .setEnabledLayerCount(0)
379                               .setPpEnabledLayerNames(nullptr)
380                               .setEnabledExtensionCount(enabled_extension_count)
381                               .setPpEnabledExtensionNames(
382                                   (const char *const *)extension_names)
383                               .setPEnabledFeatures(nullptr);
384 
385         if (separate_present_queue) {
386             queues[1].setQueueFamilyIndex(present_queue_family_index);
387             queues[1].setQueueCount(1);
388             queues[1].setPQueuePriorities(priorities);
389             deviceInfo.setQueueCreateInfoCount(2);
390         }
391 
392         auto result = gpu.createDevice(&deviceInfo, nullptr, &device);
393         VERIFY(result == vk::Result::eSuccess);
394     }
395 
destroy_texture_imageDemo396     void destroy_texture_image(texture_object *tex_objs) {
397         // clean up staging resources
398         device.freeMemory(tex_objs->mem, nullptr);
399         device.destroyImage(tex_objs->image, nullptr);
400     }
401 
drawDemo402     void draw() {
403         if (fencesInited[frame_index]) {
404             // Ensure no more than FRAME_LAG presentations are outstanding
405             device.waitForFences(1, &fences[frame_index], VK_TRUE, UINT64_MAX);
406             device.resetFences(1, &fences[frame_index]);
407         }
408 
409         // Get the index of the next available swapchain image:
410         auto result = device.acquireNextImageKHR(
411             swapchain, UINT64_MAX, image_acquired_semaphores[frame_index],
412             fences[frame_index], &current_buffer);
413         fencesInited[frame_index] = true;
414         if (result == vk::Result::eErrorOutOfDateKHR) {
415             // swapchain is out of date (e.g. the window was resized) and
416             // must be recreated:
417             frame_index += 1;
418             frame_index %= FRAME_LAG;
419 
420             resize();
421             draw();
422             return;
423         } else if (result == vk::Result::eSuboptimalKHR) {
424             // swapchain is not as optimal as it could be, but the platform's
425             // presentation engine will still present the image correctly.
426         } else {
427             VERIFY(result == vk::Result::eSuccess);
428         }
429 
430         // Wait for the image acquired semaphore to be signaled to ensure
431         // that the image won't be rendered to until the presentation
432         // engine has fully released ownership to the application, and it is
433         // okay to render to the image.
434         vk::PipelineStageFlags const pipe_stage_flags =
435             vk::PipelineStageFlagBits::eColorAttachmentOutput;
436         auto const submit_info =
437             vk::SubmitInfo()
438                 .setPWaitDstStageMask(&pipe_stage_flags)
439                 .setWaitSemaphoreCount(1)
440                 .setPWaitSemaphores(&image_acquired_semaphores[frame_index])
441                 .setCommandBufferCount(1)
442                 .setPCommandBuffers(&buffers[current_buffer].cmd)
443                 .setSignalSemaphoreCount(1)
444                 .setPSignalSemaphores(&draw_complete_semaphores[frame_index]);
445 
446         result = graphics_queue.submit(1, &submit_info, vk::Fence());
447         VERIFY(result == vk::Result::eSuccess);
448 
449         if (separate_present_queue) {
450             // If we are using separate queues, change image ownership to the
451             // present queue before presenting, waiting for the draw complete
452             // semaphore and signalling the ownership released semaphore when
453             // finished
454             auto const submit_info =
455                 vk::SubmitInfo()
456                     .setPWaitDstStageMask(&pipe_stage_flags)
457                     .setWaitSemaphoreCount(1)
458                     .setPWaitSemaphores(&draw_complete_semaphores[frame_index])
459                     .setCommandBufferCount(1)
460                     .setPCommandBuffers(
461                         &buffers[current_buffer].graphics_to_present_cmd)
462                     .setSignalSemaphoreCount(1)
463                     .setPSignalSemaphores(
464                         &image_ownership_semaphores[frame_index]);
465 
466             result = present_queue.submit(1, &submit_info, vk::Fence());
467             VERIFY(result == vk::Result::eSuccess);
468         }
469 
470         // If we are using separate queues we have to wait for image ownership,
471         // otherwise wait for draw complete
472         auto const presentInfo =
473             vk::PresentInfoKHR()
474                 .setWaitSemaphoreCount(1)
475                 .setPWaitSemaphores(
476                     separate_present_queue
477                         ? &image_ownership_semaphores[frame_index]
478                         : &draw_complete_semaphores[frame_index])
479                 .setSwapchainCount(1)
480                 .setPSwapchains(&swapchain)
481                 .setPImageIndices(&current_buffer);
482 
483         result = present_queue.presentKHR(&presentInfo);
484         frame_index += 1;
485         frame_index %= FRAME_LAG;
486         if (result == vk::Result::eErrorOutOfDateKHR) {
487             // swapchain is out of date (e.g. the window was resized) and
488             // must be recreated:
489             resize();
490         } else if (result == vk::Result::eSuboptimalKHR) {
491             // swapchain is not as optimal as it could be, but the platform's
492             // presentation engine will still present the image correctly.
493         } else {
494             VERIFY(result == vk::Result::eSuccess);
495         }
496     }
497 
draw_build_cmdDemo498     void draw_build_cmd(vk::CommandBuffer commandBuffer) {
499         auto const commandInfo = vk::CommandBufferBeginInfo().setFlags(
500             vk::CommandBufferUsageFlagBits::eSimultaneousUse);
501 
502         vk::ClearValue const clearValues[2] = {
503             vk::ClearColorValue(std::array<float, 4>({0.2f, 0.2f, 0.2f, 0.2f})),
504             vk::ClearDepthStencilValue(1.0f, 0u)};
505 
506         auto const passInfo =
507             vk::RenderPassBeginInfo()
508                 .setRenderPass(render_pass)
509                 .setFramebuffer(framebuffers[current_buffer])
510                 .setRenderArea(
511                     vk::Rect2D(vk::Offset2D(0, 0),
512                                vk::Extent2D((uint32_t)width, (uint32_t)height)))
513                 .setClearValueCount(2)
514                 .setPClearValues(clearValues);
515 
516         auto result = commandBuffer.begin(&commandInfo);
517         VERIFY(result == vk::Result::eSuccess);
518 
519         auto const image_memory_barrier =
520             vk::ImageMemoryBarrier()
521                 .setSrcAccessMask(vk::AccessFlagBits::eMemoryRead)
522                 .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
523                 .setOldLayout(vk::ImageLayout::ePresentSrcKHR)
524                 .setNewLayout(vk::ImageLayout::eColorAttachmentOptimal)
525                 .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
526                 .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
527                 .setImage(buffers[current_buffer].image)
528                 .setSubresourceRange(vk::ImageSubresourceRange(
529                     vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
530 
531         commandBuffer.pipelineBarrier(
532             vk::PipelineStageFlagBits::eColorAttachmentOutput,
533             vk::PipelineStageFlagBits::eColorAttachmentOutput,
534             vk::DependencyFlagBits(), 0, nullptr, 0, nullptr, 1,
535             &image_memory_barrier);
536 
537         commandBuffer.beginRenderPass(&passInfo, vk::SubpassContents::eInline);
538 
539         commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
540         commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
541                                          pipeline_layout, 0, 1, &desc_set, 0,
542                                          nullptr);
543 
544         auto const viewport = vk::Viewport()
545                                   .setWidth((float)width)
546                                   .setHeight((float)height)
547                                   .setMinDepth((float)0.0f)
548                                   .setMaxDepth((float)1.0f);
549         commandBuffer.setViewport(0, 1, &viewport);
550 
551         vk::Rect2D const scissor(vk::Offset2D(0, 0),
552                                  vk::Extent2D(width, height));
553         commandBuffer.setScissor(0, 1, &scissor);
554         commandBuffer.draw(12 * 3, 1, 0, 0);
555         // Note that ending the renderpass changes the image's layout from
556         // COLOR_ATTACHMENT_OPTIMAL to PRESENT_SRC_KHR
557         commandBuffer.endRenderPass();
558 
559         if (separate_present_queue) {
560             // We have to transfer ownership from the graphics queue family to
561             // the
562             // present queue family to be able to present.  Note that we don't
563             // have
564             // to transfer from present queue family back to graphics queue
565             // family at
566             // the start of the next frame because we don't care about the
567             // image's
568             // contents at that point.
569             auto const image_ownership_barrier =
570                 vk::ImageMemoryBarrier()
571                     .setSrcAccessMask(vk::AccessFlags())
572                     .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
573                     .setOldLayout(vk::ImageLayout::ePresentSrcKHR)
574                     .setNewLayout(vk::ImageLayout::ePresentSrcKHR)
575                     .setSrcQueueFamilyIndex(graphics_queue_family_index)
576                     .setDstQueueFamilyIndex(present_queue_family_index)
577                     .setImage(buffers[current_buffer].image)
578                     .setSubresourceRange(vk::ImageSubresourceRange(
579                         vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
580 
581             commandBuffer.pipelineBarrier(
582                 vk::PipelineStageFlagBits::eColorAttachmentOutput,
583                 vk::PipelineStageFlagBits::eColorAttachmentOutput,
584                 vk::DependencyFlagBits(), 0, nullptr, 0, nullptr, 1,
585                 &image_ownership_barrier);
586         }
587 
588         result = commandBuffer.end();
589         VERIFY(result == vk::Result::eSuccess);
590     }
591 
flush_init_cmdDemo592     void flush_init_cmd() {
593         // TODO: hmm.
594         // This function could get called twice if the texture uses a staging
595         // buffer
596         // In that case the second call should be ignored
597         if (!cmd) {
598             return;
599         }
600 
601         auto result = cmd.end();
602         VERIFY(result == vk::Result::eSuccess);
603 
604         auto const fenceInfo =
605             vk::FenceCreateInfo().setFlags(vk::FenceCreateFlagBits(0));
606         vk::Fence fence;
607         device.createFence(&fenceInfo, nullptr, &fence);
608 
609         vk::CommandBuffer const commandBuffers[] = {cmd};
610         auto const submitInfo =
611             vk::SubmitInfo().setCommandBufferCount(1).setPCommandBuffers(
612                 commandBuffers);
613 
614         result = graphics_queue.submit(1, &submitInfo, fence);
615         VERIFY(result == vk::Result::eSuccess);
616 
617         result = device.waitForFences(1, &fence, VK_TRUE, UINT64_MAX);
618         VERIFY(result == vk::Result::eSuccess);
619 
620         device.freeCommandBuffers(cmd_pool, 1, commandBuffers);
621         device.destroyFence(fence, nullptr);
622 
623         cmd = vk::CommandBuffer();
624     }
625 
initDemo626     void init(int argc, char **argv) {
627         vec3 eye = {0.0f, 3.0f, 5.0f};
628         vec3 origin = {0, 0, 0};
629         vec3 up = {0.0f, 1.0f, 0.0};
630 
631         frameCount = UINT32_MAX;
632         use_xlib = false;
633 
634         for (int i = 1; i < argc; i++) {
635             if (strcmp(argv[i], "--use_staging") == 0) {
636                 use_staging_buffer = true;
637                 continue;
638             }
639             if (strcmp(argv[i], "--break") == 0) {
640                 use_break = true;
641                 continue;
642             }
643             if (strcmp(argv[i], "--validate") == 0) {
644                 validate = true;
645                 continue;
646             }
647 #if defined(VK_USE_PLATFORM_XLIB_KHR)
648             if (strcmp(argv[i], "--xlib") == 0) {
649                 use_xlib = true;
650                 continue;
651             }
652 #endif
653             if (strcmp(argv[i], "--c") == 0 && frameCount == UINT32_MAX &&
654                 i < argc - 1 && sscanf(argv[i + 1], "%d", &frameCount) == 1) {
655                 i++;
656                 continue;
657             }
658             if (strcmp(argv[i], "--suppress_popups") == 0) {
659                 suppress_popups = true;
660                 continue;
661             }
662 
663             fprintf(stderr,
664                     "Usage:\n  %s [--use_staging] [--validate] [--break] "
665 #if defined(VK_USE_PLATFORM_XLIB_KHR)
666                     "[--xlib] "
667 #endif
668                     "[--c <framecount>] [--suppress_popups]\n",
669                     APP_SHORT_NAME);
670             fflush(stderr);
671             exit(1);
672         }
673 
674         if (!use_xlib) {
675             init_connection();
676         }
677 
678         init_vk();
679 
680         width = 500;
681         height = 500;
682 
683         spin_angle = 4.0f;
684         spin_increment = 0.2f;
685         pause = false;
686 
687         mat4x4_perspective(projection_matrix, (float)degreesToRadians(45.0f),
688                            1.0f, 0.1f, 100.0f);
689         mat4x4_look_at(view_matrix, eye, origin, up);
690         mat4x4_identity(model_matrix);
691 
692         projection_matrix[1][1] *=
693             -1; // Flip projection matrix from GL to Vulkan orientation.
694     }
695 
init_connectionDemo696     void init_connection() {
697 #if defined(VK_USE_PLATFORM_XCB_KHR)
698         const xcb_setup_t *setup;
699         xcb_screen_iterator_t iter;
700         int scr;
701 
702         connection = xcb_connect(nullptr, &scr);
703         if (xcb_connection_has_error(connection) > 0) {
704             printf("Cannot find a compatible Vulkan installable client driver "
705                    "(ICD).\nExiting ...\n");
706             fflush(stdout);
707             exit(1);
708         }
709 
710         setup = xcb_get_setup(connection);
711         iter = xcb_setup_roots_iterator(setup);
712         while (scr-- > 0)
713             xcb_screen_next(&iter);
714 
715         screen = iter.data;
716 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
717         display = wl_display_connect(nullptr);
718 
719         if (display == nullptr) {
720             printf("Cannot find a compatible Vulkan installable client driver "
721                    "(ICD).\nExiting ...\n");
722             fflush(stdout);
723             exit(1);
724         }
725 
726         registry = wl_display_get_registry(display);
727         wl_registry_add_listener(registry, &registry_listener, this);
728         wl_display_dispatch(display);
729 #endif
730     }
731 
init_vkDemo732     void init_vk() {
733         uint32_t instance_extension_count = 0;
734         uint32_t instance_layer_count = 0;
735         uint32_t validation_layer_count = 0;
736         char const *const *instance_validation_layers = nullptr;
737         enabled_extension_count = 0;
738         enabled_layer_count = 0;
739 
740         char const *const instance_validation_layers_alt1[] = {
741             "VK_LAYER_LUNARG_standard_validation"};
742 
743         char const *const instance_validation_layers_alt2[] = {
744             "VK_LAYER_GOOGLE_threading",
745             "VK_LAYER_LUNARG_parameter_validation",
746             "VK_LAYER_LUNARG_object_tracker",
747             "VK_LAYER_LUNARG_image",
748             "VK_LAYER_LUNARG_core_validation",
749             "VK_LAYER_LUNARG_swapchain",
750             "VK_LAYER_GOOGLE_unique_objects"};
751 
752         // Look for validation layers
753         vk::Bool32 validation_found = VK_FALSE;
754         if (validate) {
755             auto result = vk::enumerateInstanceLayerProperties(
756                 &instance_layer_count, nullptr);
757             VERIFY(result == vk::Result::eSuccess);
758 
759             instance_validation_layers = instance_validation_layers_alt1;
760             if (instance_layer_count > 0) {
761                 std::unique_ptr<vk::LayerProperties[]> instance_layers(
762                     new vk::LayerProperties[instance_layer_count]);
763                 result = vk::enumerateInstanceLayerProperties(
764                     &instance_layer_count, instance_layers.get());
765                 VERIFY(result == vk::Result::eSuccess);
766 
767                 validation_found =
768                     check_layers(ARRAY_SIZE(instance_validation_layers_alt1),
769                                  instance_validation_layers,
770                                  instance_layer_count, instance_layers.get());
771                 if (validation_found) {
772                     enabled_layer_count =
773                         ARRAY_SIZE(instance_validation_layers_alt1);
774                     enabled_layers[0] = "VK_LAYER_LUNARG_standard_validation";
775                     validation_layer_count = 1;
776                 } else {
777                     // use alternative set of validation layers
778                     instance_validation_layers =
779                         instance_validation_layers_alt2;
780                     enabled_layer_count =
781                         ARRAY_SIZE(instance_validation_layers_alt2);
782                     validation_found = check_layers(
783                         ARRAY_SIZE(instance_validation_layers_alt2),
784                         instance_validation_layers, instance_layer_count,
785                         instance_layers.get());
786                     validation_layer_count =
787                         ARRAY_SIZE(instance_validation_layers_alt2);
788                     for (uint32_t i = 0; i < validation_layer_count; i++) {
789                         enabled_layers[i] = instance_validation_layers[i];
790                     }
791                 }
792             }
793 
794             if (!validation_found) {
795                 ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find "
796                          "required validation layer.\n\n"
797                          "Please look at the Getting Started guide for "
798                          "additional information.\n",
799                          "vkCreateInstance Failure");
800             }
801         }
802 
803         /* Look for instance extensions */
804         vk::Bool32 surfaceExtFound = VK_FALSE;
805         vk::Bool32 platformSurfaceExtFound = VK_FALSE;
806 #if defined(VK_USE_PLATFORM_XLIB_KHR)
807         vk::Bool32 xlibSurfaceExtFound = VK_FALSE;
808 #endif
809         memset(extension_names, 0, sizeof(extension_names));
810 
811         auto result = vk::enumerateInstanceExtensionProperties(
812             nullptr, &instance_extension_count, nullptr);
813         VERIFY(result == vk::Result::eSuccess);
814 
815         if (instance_extension_count > 0) {
816             std::unique_ptr<vk::ExtensionProperties[]> instance_extensions(
817                 new vk::ExtensionProperties[instance_extension_count]);
818             result = vk::enumerateInstanceExtensionProperties(
819                 nullptr, &instance_extension_count, instance_extensions.get());
820             VERIFY(result == vk::Result::eSuccess);
821 
822             for (uint32_t i = 0; i < instance_extension_count; i++) {
823                 if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME,
824                             instance_extensions[i].extensionName)) {
825                     surfaceExtFound = 1;
826                     extension_names[enabled_extension_count++] =
827                         VK_KHR_SURFACE_EXTENSION_NAME;
828                 }
829 #if defined(VK_USE_PLATFORM_WIN32_KHR)
830                 if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
831                             instance_extensions[i].extensionName)) {
832                     platformSurfaceExtFound = 1;
833                     extension_names[enabled_extension_count++] =
834                         VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
835                 }
836 #endif
837 #if defined(VK_USE_PLATFORM_XLIB_KHR)
838                 if (!strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
839                             instance_extensions[i].extensionName)) {
840                     platformSurfaceExtFound = 1;
841                     xlibSurfaceExtFound = 1;
842                     extension_names[enabled_extension_count++] =
843                         VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
844                 }
845 #endif
846 #if defined(VK_USE_PLATFORM_XCB_KHR)
847                 if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME,
848                             instance_extensions[i].extensionName)) {
849                     platformSurfaceExtFound = 1;
850                     extension_names[enabled_extension_count++] =
851                         VK_KHR_XCB_SURFACE_EXTENSION_NAME;
852                 }
853 #endif
854 #if defined(VK_USE_PLATFORM_WAYLAND_KHR)
855                 if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
856                             instance_extensions[i].extensionName)) {
857                     platformSurfaceExtFound = 1;
858                     extension_names[enabled_extension_count++] =
859                         VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
860                 }
861 #endif
862                 assert(enabled_extension_count < 64);
863             }
864         }
865 
866         if (!surfaceExtFound) {
867             ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
868                      "the " VK_KHR_SURFACE_EXTENSION_NAME " extension.\n\n"
869                      "Do you have a compatible Vulkan installable client "
870                      "driver (ICD) installed?\n"
871                      "Please look at the Getting Started guide for additional "
872                      "information.\n",
873                      "vkCreateInstance Failure");
874         }
875 
876         if (!platformSurfaceExtFound) {
877 #if defined(VK_USE_PLATFORM_WIN32_KHR)
878             ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
879                      "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME
880                      " extension.\n\n"
881                      "Do you have a compatible Vulkan installable client "
882                      "driver (ICD) installed?\n"
883                      "Please look at the Getting Started guide for additional "
884                      "information.\n",
885                      "vkCreateInstance Failure");
886 #elif defined(VK_USE_PLATFORM_XCB_KHR)
887             ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
888                      "the " VK_KHR_XCB_SURFACE_EXTENSION_NAME " extension.\n\n"
889                      "Do you have a compatible Vulkan installable client "
890                      "driver (ICD) installed?\n"
891                      "Please look at the Getting Started guide for additional "
892                      "information.\n",
893                      "vkCreateInstance Failure");
894 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
895             ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
896                      "the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
897                      " extension.\n\n"
898                      "Do you have a compatible Vulkan installable client "
899                      "driver (ICD) installed?\n"
900                      "Please look at the Getting Started guide for additional "
901                      "information.\n",
902                      "vkCreateInstance Failure");
903 #endif
904         }
905 
906 #if defined(VK_USE_PLATFORM_XLIB_KHR)
907         if (use_xlib && !xlibSurfaceExtFound) {
908             ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
909                      "the " VK_KHR_XLIB_SURFACE_EXTENSION_NAME " extension.\n\n"
910                      "Do you have a compatible Vulkan installable client "
911                      "driver (ICD) installed?\n"
912                      "Please look at the Getting Started guide for additional "
913                      "information.\n",
914                      "vkCreateInstance Failure");
915         }
916 #endif
917 
918         auto const app = vk::ApplicationInfo()
919                              .setPApplicationName(APP_SHORT_NAME)
920                              .setApplicationVersion(0)
921                              .setPEngineName(APP_SHORT_NAME)
922                              .setEngineVersion(0)
923                              .setApiVersion(VK_API_VERSION_1_0);
924         auto const inst_info =
925             vk::InstanceCreateInfo()
926                 .setPApplicationInfo(&app)
927                 .setEnabledLayerCount(enabled_layer_count)
928                 .setPpEnabledLayerNames(instance_validation_layers)
929                 .setEnabledExtensionCount(enabled_extension_count)
930                 .setPpEnabledExtensionNames(extension_names);
931 
932         result = vk::createInstance(&inst_info, nullptr, &inst);
933         if (result == vk::Result::eErrorIncompatibleDriver) {
934             ERR_EXIT("Cannot find a compatible Vulkan installable client "
935                      "driver (ICD).\n\n"
936                      "Please look at the Getting Started guide for additional "
937                      "information.\n",
938                      "vkCreateInstance Failure");
939         } else if (result == vk::Result::eErrorExtensionNotPresent) {
940             ERR_EXIT("Cannot find a specified extension library.\n"
941                      "Make sure your layers path is set appropriately.\n",
942                      "vkCreateInstance Failure");
943         } else if (result != vk::Result::eSuccess) {
944             ERR_EXIT("vkCreateInstance failed.\n\n"
945                      "Do you have a compatible Vulkan installable client "
946                      "driver (ICD) installed?\n"
947                      "Please look at the Getting Started guide for additional "
948                      "information.\n",
949                      "vkCreateInstance Failure");
950         }
951 
952         /* Make initial call to query gpu_count, then second call for gpu info*/
953         uint32_t gpu_count;
954         result = inst.enumeratePhysicalDevices(&gpu_count, nullptr);
955         VERIFY(result == vk::Result::eSuccess);
956         assert(gpu_count > 0);
957 
958         if (gpu_count > 0) {
959             std::unique_ptr<vk::PhysicalDevice[]> physical_devices(
960                 new vk::PhysicalDevice[gpu_count]);
961             result = inst.enumeratePhysicalDevices(&gpu_count,
962                                                    physical_devices.get());
963             VERIFY(result == vk::Result::eSuccess);
964             /* For cube demo we just grab the first physical device */
965             gpu = physical_devices[0];
966         } else {
967             ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible "
968                      "devices.\n\n"
969                      "Do you have a compatible Vulkan installable client "
970                      "driver (ICD) installed?\n"
971                      "Please look at the Getting Started guide for additional "
972                      "information.\n",
973                      "vkEnumeratePhysicalDevices Failure");
974         }
975 
976         /* Look for device extensions */
977         uint32_t device_extension_count = 0;
978         vk::Bool32 swapchainExtFound = VK_FALSE;
979         enabled_extension_count = 0;
980         memset(extension_names, 0, sizeof(extension_names));
981 
982         result = gpu.enumerateDeviceExtensionProperties(
983             nullptr, &device_extension_count, nullptr);
984         VERIFY(result == vk::Result::eSuccess);
985 
986         if (device_extension_count > 0) {
987             std::unique_ptr<vk::ExtensionProperties[]> device_extensions(
988                 new vk::ExtensionProperties[device_extension_count]);
989             result = gpu.enumerateDeviceExtensionProperties(
990                 nullptr, &device_extension_count, device_extensions.get());
991             VERIFY(result == vk::Result::eSuccess);
992 
993             for (uint32_t i = 0; i < device_extension_count; i++) {
994                 if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,
995                             device_extensions[i].extensionName)) {
996                     swapchainExtFound = 1;
997                     extension_names[enabled_extension_count++] =
998                         VK_KHR_SWAPCHAIN_EXTENSION_NAME;
999                 }
1000                 assert(enabled_extension_count < 64);
1001             }
1002         }
1003 
1004         if (!swapchainExtFound) {
1005             ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find "
1006                      "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME " extension.\n\n"
1007                      "Do you have a compatible Vulkan installable client "
1008                      "driver (ICD) installed?\n"
1009                      "Please look at the Getting Started guide for additional "
1010                      "information.\n",
1011                      "vkCreateInstance Failure");
1012         }
1013 
1014         gpu.getProperties(&gpu_props);
1015 
1016         /* Call with nullptr data to get count */
1017         gpu.getQueueFamilyProperties(&queue_family_count, nullptr);
1018         assert(queue_family_count >= 1);
1019 
1020         queue_props.reset(new vk::QueueFamilyProperties[queue_family_count]);
1021         gpu.getQueueFamilyProperties(&queue_family_count, queue_props.get());
1022 
1023         // Query fine-grained feature support for this device.
1024         //  If app has specific feature requirements it should check supported
1025         //  features based on this query
1026         vk::PhysicalDeviceFeatures physDevFeatures;
1027         gpu.getFeatures(&physDevFeatures);
1028     }
1029 
init_vk_swapchainDemo1030     void init_vk_swapchain() {
1031 // Create a WSI surface for the window:
1032 #if defined(VK_USE_PLATFORM_WIN32_KHR)
1033         {
1034             auto const createInfo = vk::Win32SurfaceCreateInfoKHR()
1035                                         .setHinstance(connection)
1036                                         .setHwnd(window);
1037 
1038             auto result =
1039                 inst.createWin32SurfaceKHR(&createInfo, nullptr, &surface);
1040             VERIFY(result == vk::Result::eSuccess);
1041         }
1042 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) && !defined(VK_USE_PLATFORM_XCB_KHR)
1043         {
1044             auto const createInfo = vk::WaylandSurfaceCreateInfoKHR()
1045                                         .setDisplay(display)
1046                                         .setSurface(window);
1047 
1048             auto result =
1049                 inst.createWaylandSurfaceKHR(&createInfo, nullptr, &surface);
1050             VERIFY(result == vk::Result::eSuccess);
1051         }
1052 #endif
1053         if (use_xlib) {
1054 #if defined(VK_USE_PLATFORM_XLIB_KHR)
1055             auto const createInfo =
1056                 vk::XlibSurfaceCreateInfoKHR().setDpy(display).setWindow(
1057                     xlib_window);
1058 
1059             auto result =
1060                 inst.createXlibSurfaceKHR(&createInfo, nullptr, &surface);
1061             VERIFY(result == vk::Result::eSuccess);
1062 #endif
1063         } else {
1064 #if defined(VK_USE_PLATFORM_XCB_KHR)
1065             auto const createInfo = vk::XcbSurfaceCreateInfoKHR()
1066                                         .setConnection(connection)
1067                                         .setWindow(xcb_window);
1068 
1069             auto result =
1070                 inst.createXcbSurfaceKHR(&createInfo, nullptr, &surface);
1071             VERIFY(result == vk::Result::eSuccess);
1072 #endif
1073         }
1074 
1075         // Iterate over each queue to learn whether it supports presenting:
1076         std::unique_ptr<vk::Bool32[]> supportsPresent(
1077             new vk::Bool32[queue_family_count]);
1078         for (uint32_t i = 0; i < queue_family_count; i++) {
1079             gpu.getSurfaceSupportKHR(i, surface, &supportsPresent[i]);
1080         }
1081 
1082         uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
1083         uint32_t presentQueueFamilyIndex = UINT32_MAX;
1084         for (uint32_t i = 0; i < queue_family_count; i++) {
1085             if (queue_props[i].queueFlags & vk::QueueFlagBits::eGraphics) {
1086                 if (graphicsQueueFamilyIndex == UINT32_MAX) {
1087                     graphicsQueueFamilyIndex = i;
1088                 }
1089 
1090                 if (supportsPresent[i] == VK_TRUE) {
1091                     graphicsQueueFamilyIndex = i;
1092                     presentQueueFamilyIndex = i;
1093                     break;
1094                 }
1095             }
1096         }
1097 
1098         if (presentQueueFamilyIndex == UINT32_MAX) {
1099             // If didn't find a queue that supports both graphics and present,
1100             // then
1101             // find a separate present queue.
1102             for (uint32_t i = 0; i < queue_family_count; ++i) {
1103                 if (supportsPresent[i] == VK_TRUE) {
1104                     presentQueueFamilyIndex = i;
1105                     break;
1106                 }
1107             }
1108         }
1109 
1110         // Generate error if could not find both a graphics and a present queue
1111         if (graphicsQueueFamilyIndex == UINT32_MAX ||
1112             presentQueueFamilyIndex == UINT32_MAX) {
1113             ERR_EXIT("Could not find both graphics and present queues\n",
1114                      "Swapchain Initialization Failure");
1115         }
1116 
1117         graphics_queue_family_index = graphicsQueueFamilyIndex;
1118         present_queue_family_index = presentQueueFamilyIndex;
1119         separate_present_queue =
1120             (graphics_queue_family_index != present_queue_family_index);
1121 
1122         create_device();
1123 
1124         device.getQueue(graphics_queue_family_index, 0, &graphics_queue);
1125         if (!separate_present_queue) {
1126             present_queue = graphics_queue;
1127         } else {
1128             device.getQueue(present_queue_family_index, 0, &present_queue);
1129         }
1130 
1131         // Get the list of VkFormat's that are supported:
1132         uint32_t formatCount;
1133         auto result = gpu.getSurfaceFormatsKHR(surface, &formatCount, nullptr);
1134         VERIFY(result == vk::Result::eSuccess);
1135 
1136         std::unique_ptr<vk::SurfaceFormatKHR[]> surfFormats(
1137             new vk::SurfaceFormatKHR[formatCount]);
1138         result =
1139             gpu.getSurfaceFormatsKHR(surface, &formatCount, surfFormats.get());
1140         VERIFY(result == vk::Result::eSuccess);
1141 
1142         // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
1143         // the surface has no preferred format.  Otherwise, at least one
1144         // supported format will be returned.
1145         if (formatCount == 1 &&
1146             surfFormats[0].format == vk::Format::eUndefined) {
1147             format = vk::Format::eB8G8R8A8Unorm;
1148         } else {
1149             assert(formatCount >= 1);
1150             format = surfFormats[0].format;
1151         }
1152         color_space = surfFormats[0].colorSpace;
1153 
1154         quit = false;
1155         curFrame = 0;
1156 
1157         // Create semaphores to synchronize acquiring presentable buffers before
1158         // rendering and waiting for drawing to be complete before presenting
1159         auto const semaphoreCreateInfo = vk::SemaphoreCreateInfo();
1160 
1161         // Create fences that we can use to throttle if we get too far
1162         // ahead of the image presents
1163         vk::FenceCreateInfo const fence_ci;
1164         for (uint32_t i = 0; i < FRAME_LAG; i++) {
1165             device.createFence(&fence_ci, nullptr, &fences[i]);
1166             fencesInited[i] = false;
1167             result = device.createSemaphore(&semaphoreCreateInfo, nullptr,
1168                                             &image_acquired_semaphores[i]);
1169             VERIFY(result == vk::Result::eSuccess);
1170 
1171             result = device.createSemaphore(&semaphoreCreateInfo, nullptr,
1172                                             &draw_complete_semaphores[i]);
1173             VERIFY(result == vk::Result::eSuccess);
1174 
1175             if (separate_present_queue) {
1176                 result = device.createSemaphore(&semaphoreCreateInfo, nullptr,
1177                                                 &image_ownership_semaphores[i]);
1178                 VERIFY(result == vk::Result::eSuccess);
1179             }
1180         }
1181         frame_index = 0;
1182 
1183         // Get Memory information and properties
1184         gpu.getMemoryProperties(&memory_properties);
1185     }
1186 
prepareDemo1187     void prepare() {
1188         auto const cmd_pool_info =
1189             vk::CommandPoolCreateInfo().setQueueFamilyIndex(
1190                 graphics_queue_family_index);
1191         auto result =
1192             device.createCommandPool(&cmd_pool_info, nullptr, &cmd_pool);
1193         VERIFY(result == vk::Result::eSuccess);
1194 
1195         auto const cmd = vk::CommandBufferAllocateInfo()
1196                              .setCommandPool(cmd_pool)
1197                              .setLevel(vk::CommandBufferLevel::ePrimary)
1198                              .setCommandBufferCount(1);
1199 
1200         prepare_buffers();
1201         prepare_depth();
1202         prepare_textures();
1203         prepare_cube_data_buffer();
1204 
1205         prepare_descriptor_layout();
1206         prepare_render_pass();
1207         prepare_pipeline();
1208 
1209         for (uint32_t i = 0; i < swapchainImageCount; ++i) {
1210             result = device.allocateCommandBuffers(&cmd, &buffers[i].cmd);
1211             VERIFY(result == vk::Result::eSuccess);
1212         }
1213 
1214         if (separate_present_queue) {
1215             auto const cmd_pool_info =
1216                 vk::CommandPoolCreateInfo().setQueueFamilyIndex(
1217                     present_queue_family_index);
1218 
1219             result = device.createCommandPool(&cmd_pool_info, nullptr,
1220                                               &present_cmd_pool);
1221             VERIFY(result == vk::Result::eSuccess);
1222 
1223             auto const cmd = vk::CommandBufferAllocateInfo()
1224                                  .setCommandPool(present_cmd_pool)
1225                                  .setLevel(vk::CommandBufferLevel::ePrimary)
1226                                  .setCommandBufferCount(1);
1227 
1228             for (uint32_t i = 0; i < swapchainImageCount; i++) {
1229                 result = device.allocateCommandBuffers(
1230                     &cmd, &buffers[i].graphics_to_present_cmd);
1231                 VERIFY(result == vk::Result::eSuccess);
1232 
1233                 build_image_ownership_cmd(i);
1234             }
1235         }
1236 
1237         prepare_descriptor_pool();
1238         prepare_descriptor_set();
1239 
1240         prepare_framebuffers();
1241 
1242         for (uint32_t i = 0; i < swapchainImageCount; ++i) {
1243             current_buffer = i;
1244             draw_build_cmd(buffers[i].cmd);
1245         }
1246 
1247         /*
1248          * Prepare functions above may generate pipeline commands
1249          * that need to be flushed before beginning the render loop.
1250          */
1251         flush_init_cmd();
1252 
1253         current_buffer = 0;
1254         prepared = true;
1255     }
1256 
prepare_buffersDemo1257     void prepare_buffers() {
1258         vk::SwapchainKHR oldSwapchain = swapchain;
1259 
1260         // Check the surface capabilities and formats
1261         vk::SurfaceCapabilitiesKHR surfCapabilities;
1262         auto result = gpu.getSurfaceCapabilitiesKHR(surface, &surfCapabilities);
1263         VERIFY(result == vk::Result::eSuccess);
1264 
1265         uint32_t presentModeCount;
1266         result =
1267             gpu.getSurfacePresentModesKHR(surface, &presentModeCount, nullptr);
1268         VERIFY(result == vk::Result::eSuccess);
1269 
1270         std::unique_ptr<vk::PresentModeKHR[]> presentModes(
1271             new vk::PresentModeKHR[presentModeCount]);
1272         result = gpu.getSurfacePresentModesKHR(surface, &presentModeCount,
1273                                                presentModes.get());
1274         VERIFY(result == vk::Result::eSuccess);
1275 
1276         vk::Extent2D swapchainExtent;
1277         // width and height are either both -1, or both not -1.
1278         if (surfCapabilities.currentExtent.width == (uint32_t)-1) {
1279             // If the surface size is undefined, the size is set to
1280             // the size of the images requested.
1281             swapchainExtent.width = width;
1282             swapchainExtent.height = height;
1283         } else {
1284             // If the surface size is defined, the swap chain size must match
1285             swapchainExtent = surfCapabilities.currentExtent;
1286             width = surfCapabilities.currentExtent.width;
1287             height = surfCapabilities.currentExtent.height;
1288         }
1289 
1290         // The FIFO present mode is guaranteed by the spec to be supported
1291         // and to have no tearing.  It's a great default present mode to use.
1292         vk::PresentModeKHR swapchainPresentMode = vk::PresentModeKHR::eFifo;
1293 
1294 //  There are times when you may wish to use another present mode.  The
1295 //  following code shows how to select them, and the comments provide some
1296 //  reasons you may wish to use them.
1297 //
1298 // It should be noted that Vulkan 1.0 doesn't provide a method for
1299 // synchronizing rendering with the presentation engine's display.  There
1300 // is a method provided for throttling rendering with the display, but
1301 // there are some presentation engines for which this method will not work.
1302 // If an application doesn't throttle its rendering, and if it renders much
1303 // faster than the refresh rate of the display, this can waste power on
1304 // mobile devices.  That is because power is being spent rendering images
1305 // that may never be seen.
1306 //#define DESIRE_VK_PRESENT_MODE_IMMEDIATE_KHR
1307 //#define DESIRE_VK_PRESENT_MODE_MAILBOX_KHR
1308 //#define DESIRE_VK_PRESENT_MODE_FIFO_RELAXED_KHR
1309 #if defined(DESIRE_VK_PRESENT_MODE_IMMEDIATE_KHR)
1310         // VK_PRESENT_MODE_IMMEDIATE_KHR is for applications that don't care
1311         // about
1312         // tearing, or have some way of synchronizing their rendering with the
1313         // display.
1314         for (size_t i = 0; i < presentModeCount; ++i) {
1315             if (presentModes[i] == vk::PresentModeKHR::eImmediate) {
1316                 swapchainPresentMode = vk::PresentModeKHR::eImmediate;
1317                 break;
1318             }
1319         }
1320 #elif defined(DESIRE_VK_PRESENT_MODE_MAILBOX_KHR)
1321         // VK_PRESENT_MODE_MAILBOX_KHR may be useful for applications that
1322         // generally render a new presentable image every refresh cycle, but are
1323         // occasionally early.  In this case, the application wants the new
1324         // image
1325         // to be displayed instead of the previously-queued-for-presentation
1326         // image
1327         // that has not yet been displayed.
1328         for (size_t i = 0; i < presentModeCount; ++i) {
1329             if (presentModes[i] == vk::PresentModeKHR::eMailbox) {
1330                 swapchainPresentMode = vk::PresentModeKHR::eMailbox;
1331                 break;
1332             }
1333         }
1334 #elif defined(DESIRE_VK_PRESENT_MODE_FIFO_RELAXED_KHR)
1335         // VK_PRESENT_MODE_FIFO_RELAXED_KHR is for applications that generally
1336         // render a new presentable image every refresh cycle, but are
1337         // occasionally
1338         // late.  In this case (perhaps because of stuttering/latency concerns),
1339         // the application wants the late image to be immediately displayed,
1340         // even
1341         // though that may mean some tearing.
1342         for (size_t i = 0; i < presentModeCount; ++i) {
1343             if (presentModes[i] == vk::PresentModeKHR::eFifoRelaxed) {
1344                 swapchainPresentMode = vk::PresentModeKHR::eFifoRelaxed;
1345                 break;
1346             }
1347         }
1348 #endif
1349 
1350         // Determine the number of VkImage's to use in the swap chain (we desire
1351         // to
1352         // own only 1 image at a time, besides the images being displayed and
1353         // queued for display):
1354         uint32_t desiredNumberOfSwapchainImages =
1355             surfCapabilities.minImageCount + 1;
1356         // If maxImageCount is 0, we can ask for as many images as we want,
1357         // otherwise
1358         // we're limited to maxImageCount
1359         if ((surfCapabilities.maxImageCount > 0) &&
1360             (desiredNumberOfSwapchainImages > surfCapabilities.maxImageCount)) {
1361             // Application must settle for fewer images than desired:
1362             desiredNumberOfSwapchainImages = surfCapabilities.maxImageCount;
1363         }
1364 
1365         vk::SurfaceTransformFlagBitsKHR preTransform;
1366         if (surfCapabilities.supportedTransforms &
1367             vk::SurfaceTransformFlagBitsKHR::eIdentity) {
1368             preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
1369         } else {
1370             preTransform = surfCapabilities.currentTransform;
1371         }
1372 
1373         auto const swapchain_ci =
1374             vk::SwapchainCreateInfoKHR()
1375                 .setSurface(surface)
1376                 .setMinImageCount(desiredNumberOfSwapchainImages)
1377                 .setImageFormat(format)
1378                 .setImageColorSpace(color_space)
1379                 .setImageExtent({swapchainExtent.width, swapchainExtent.height})
1380                 .setImageArrayLayers(1)
1381                 .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment)
1382                 .setImageSharingMode(vk::SharingMode::eExclusive)
1383                 .setQueueFamilyIndexCount(0)
1384                 .setPQueueFamilyIndices(nullptr)
1385                 .setPreTransform(preTransform)
1386                 .setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque)
1387                 .setPresentMode(swapchainPresentMode)
1388                 .setClipped(true)
1389                 .setOldSwapchain(oldSwapchain);
1390 
1391         result = device.createSwapchainKHR(&swapchain_ci, nullptr, &swapchain);
1392         VERIFY(result == vk::Result::eSuccess);
1393 
1394         // If we just re-created an existing swapchain, we should destroy the
1395         // old
1396         // swapchain at this point.
1397         // Note: destroying the swapchain also cleans up all its associated
1398         // presentable images once the platform is done with them.
1399         if (oldSwapchain) {
1400             device.destroySwapchainKHR(oldSwapchain, nullptr);
1401         }
1402 
1403         result = device.getSwapchainImagesKHR(swapchain, &swapchainImageCount,
1404                                               nullptr);
1405         VERIFY(result == vk::Result::eSuccess);
1406 
1407         std::unique_ptr<vk::Image[]> swapchainImages(
1408             new vk::Image[swapchainImageCount]);
1409         result = device.getSwapchainImagesKHR(swapchain, &swapchainImageCount,
1410                                               swapchainImages.get());
1411         VERIFY(result == vk::Result::eSuccess);
1412 
1413         buffers.reset(new SwapchainBuffers[swapchainImageCount]);
1414 
1415         for (uint32_t i = 0; i < swapchainImageCount; ++i) {
1416             auto const color_image_view =
1417                 vk::ImageViewCreateInfo()
1418                     .setImage(swapchainImages[i])
1419                     .setViewType(vk::ImageViewType::e2D)
1420                     .setFormat(format)
1421                     .setSubresourceRange(vk::ImageSubresourceRange(
1422                         vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
1423 
1424             buffers[i].image = swapchainImages[i];
1425 
1426             result = device.createImageView(&color_image_view, nullptr,
1427                                             &buffers[i].view);
1428             VERIFY(result == vk::Result::eSuccess);
1429 
1430             // The draw loop will be expecting the presentable images to be in
1431             // LAYOUT_PRESENT_SRC_KHR since that's how they're left at the end
1432             // of every frame.
1433             set_image_layout(buffers[i].image, vk::ImageAspectFlagBits::eColor,
1434                              vk::ImageLayout::eUndefined,
1435                              vk::ImageLayout::ePresentSrcKHR,
1436                              vk::AccessFlagBits());
1437         }
1438     }
1439 
prepare_cube_data_bufferDemo1440     void prepare_cube_data_buffer() {
1441         mat4x4 VP;
1442         mat4x4_mul(VP, projection_matrix, view_matrix);
1443 
1444         mat4x4 MVP;
1445         mat4x4_mul(MVP, VP, model_matrix);
1446 
1447         vktexcube_vs_uniform data;
1448         memcpy(data.mvp, MVP, sizeof(MVP));
1449         //    dumpMatrix("MVP", MVP)
1450         for (int32_t i = 0; i < 12 * 3; i++) {
1451             data.position[i][0] = g_vertex_buffer_data[i * 3];
1452             data.position[i][1] = g_vertex_buffer_data[i * 3 + 1];
1453             data.position[i][2] = g_vertex_buffer_data[i * 3 + 2];
1454             data.position[i][3] = 1.0f;
1455             data.attr[i][0] = g_uv_buffer_data[2 * i];
1456             data.attr[i][1] = g_uv_buffer_data[2 * i + 1];
1457             data.attr[i][2] = 0;
1458             data.attr[i][3] = 0;
1459         }
1460 
1461         auto const buf_info =
1462             vk::BufferCreateInfo()
1463                 .setSize(sizeof(data))
1464                 .setUsage(vk::BufferUsageFlagBits::eUniformBuffer);
1465         auto result =
1466             device.createBuffer(&buf_info, nullptr, &uniform_data.buf);
1467         VERIFY(result == vk::Result::eSuccess);
1468 
1469         vk::MemoryRequirements mem_reqs;
1470         device.getBufferMemoryRequirements(uniform_data.buf, &mem_reqs);
1471 
1472         uniform_data.mem_alloc.setAllocationSize(mem_reqs.size);
1473         uniform_data.mem_alloc.setMemoryTypeIndex(0);
1474 
1475         bool const pass = memory_type_from_properties(
1476             mem_reqs.memoryTypeBits,
1477             vk::MemoryPropertyFlagBits::eHostVisible |
1478                 vk::MemoryPropertyFlagBits::eHostCoherent,
1479             &uniform_data.mem_alloc.memoryTypeIndex);
1480         VERIFY(pass);
1481 
1482         result = device.allocateMemory(&uniform_data.mem_alloc, nullptr,
1483                                        &(uniform_data.mem));
1484         VERIFY(result == vk::Result::eSuccess);
1485 
1486         auto pData = device.mapMemory(uniform_data.mem, 0,
1487                                       uniform_data.mem_alloc.allocationSize,
1488                                       vk::MemoryMapFlags());
1489         VERIFY(pData.result == vk::Result::eSuccess);
1490 
1491         memcpy(pData.value, &data, sizeof data);
1492 
1493         device.unmapMemory(uniform_data.mem);
1494 
1495         result = device.bindBufferMemory(uniform_data.buf, uniform_data.mem, 0);
1496         VERIFY(result == vk::Result::eSuccess);
1497 
1498         uniform_data.buffer_info.buffer = uniform_data.buf;
1499         uniform_data.buffer_info.offset = 0;
1500         uniform_data.buffer_info.range = sizeof(data);
1501     }
1502 
prepare_depthDemo1503     void prepare_depth() {
1504         depth.format = vk::Format::eD16Unorm;
1505 
1506         auto const image =
1507             vk::ImageCreateInfo()
1508                 .setImageType(vk::ImageType::e2D)
1509                 .setFormat(depth.format)
1510                 .setExtent({(uint32_t)width, (uint32_t)height, 1})
1511                 .setMipLevels(1)
1512                 .setArrayLayers(1)
1513                 .setSamples(vk::SampleCountFlagBits::e1)
1514                 .setTiling(vk::ImageTiling::eOptimal)
1515                 .setUsage(vk::ImageUsageFlagBits::eDepthStencilAttachment)
1516                 .setSharingMode(vk::SharingMode::eExclusive)
1517                 .setQueueFamilyIndexCount(0)
1518                 .setPQueueFamilyIndices(nullptr)
1519                 .setInitialLayout(vk::ImageLayout::eUndefined);
1520 
1521         auto result = device.createImage(&image, nullptr, &depth.image);
1522         VERIFY(result == vk::Result::eSuccess);
1523 
1524         vk::MemoryRequirements mem_reqs;
1525         device.getImageMemoryRequirements(depth.image, &mem_reqs);
1526 
1527         depth.mem_alloc.setAllocationSize(mem_reqs.size);
1528         depth.mem_alloc.setMemoryTypeIndex(0);
1529 
1530         auto const pass = memory_type_from_properties(
1531             mem_reqs.memoryTypeBits, vk::MemoryPropertyFlagBits(0),
1532             &depth.mem_alloc.memoryTypeIndex);
1533         VERIFY(pass);
1534 
1535         result = device.allocateMemory(&depth.mem_alloc, nullptr, &depth.mem);
1536         VERIFY(result == vk::Result::eSuccess);
1537 
1538         result = device.bindImageMemory(depth.image, depth.mem, 0);
1539         VERIFY(result == vk::Result::eSuccess);
1540 
1541         set_image_layout(depth.image, vk::ImageAspectFlagBits::eDepth,
1542                          vk::ImageLayout::eUndefined,
1543                          vk::ImageLayout::eDepthStencilAttachmentOptimal,
1544                          vk::AccessFlagBits());
1545 
1546         auto const view = vk::ImageViewCreateInfo()
1547                               .setImage(depth.image)
1548                               .setViewType(vk::ImageViewType::e2D)
1549                               .setFormat(depth.format)
1550                               .setSubresourceRange(vk::ImageSubresourceRange(
1551                                   vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1));
1552         result = device.createImageView(&view, nullptr, &depth.view);
1553         VERIFY(result == vk::Result::eSuccess);
1554     }
1555 
prepare_descriptor_layoutDemo1556     void prepare_descriptor_layout() {
1557         vk::DescriptorSetLayoutBinding const layout_bindings[2] = {
1558             vk::DescriptorSetLayoutBinding()
1559                 .setBinding(0)
1560                 .setDescriptorType(vk::DescriptorType::eUniformBuffer)
1561                 .setDescriptorCount(1)
1562                 .setStageFlags(vk::ShaderStageFlagBits::eVertex)
1563                 .setPImmutableSamplers(nullptr),
1564             vk::DescriptorSetLayoutBinding()
1565                 .setBinding(1)
1566                 .setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
1567                 .setDescriptorCount(texture_count)
1568                 .setStageFlags(vk::ShaderStageFlagBits::eFragment)
1569                 .setPImmutableSamplers(nullptr)};
1570 
1571         auto const descriptor_layout =
1572             vk::DescriptorSetLayoutCreateInfo().setBindingCount(2).setPBindings(
1573                 layout_bindings);
1574 
1575         auto result = device.createDescriptorSetLayout(&descriptor_layout,
1576                                                        nullptr, &desc_layout);
1577         VERIFY(result == vk::Result::eSuccess);
1578 
1579         auto const pPipelineLayoutCreateInfo =
1580             vk::PipelineLayoutCreateInfo().setSetLayoutCount(1).setPSetLayouts(
1581                 &desc_layout);
1582 
1583         result = device.createPipelineLayout(&pPipelineLayoutCreateInfo,
1584                                              nullptr, &pipeline_layout);
1585         VERIFY(result == vk::Result::eSuccess);
1586     }
1587 
prepare_descriptor_poolDemo1588     void prepare_descriptor_pool() {
1589         vk::DescriptorPoolSize const poolSizes[2] = {
1590             vk::DescriptorPoolSize()
1591                 .setType(vk::DescriptorType::eUniformBuffer)
1592                 .setDescriptorCount(1),
1593             vk::DescriptorPoolSize()
1594                 .setType(vk::DescriptorType::eCombinedImageSampler)
1595                 .setDescriptorCount(texture_count)};
1596 
1597         auto const descriptor_pool = vk::DescriptorPoolCreateInfo()
1598                                          .setMaxSets(1)
1599                                          .setPoolSizeCount(2)
1600                                          .setPPoolSizes(poolSizes);
1601 
1602         auto result =
1603             device.createDescriptorPool(&descriptor_pool, nullptr, &desc_pool);
1604         VERIFY(result == vk::Result::eSuccess);
1605     }
1606 
prepare_descriptor_setDemo1607     void prepare_descriptor_set() {
1608         auto const alloc_info = vk::DescriptorSetAllocateInfo()
1609                                     .setDescriptorPool(desc_pool)
1610                                     .setDescriptorSetCount(1)
1611                                     .setPSetLayouts(&desc_layout);
1612         auto result = device.allocateDescriptorSets(&alloc_info, &desc_set);
1613         VERIFY(result == vk::Result::eSuccess);
1614 
1615         vk::DescriptorImageInfo tex_descs[texture_count];
1616         for (uint32_t i = 0; i < texture_count; i++) {
1617             tex_descs[i].setSampler(textures[i].sampler);
1618             tex_descs[i].setImageView(textures[i].view);
1619             tex_descs[i].setImageLayout(vk::ImageLayout::eGeneral);
1620         }
1621 
1622         vk::WriteDescriptorSet writes[2];
1623 
1624         writes[0].setDstSet(desc_set);
1625         writes[0].setDescriptorCount(1);
1626         writes[0].setDescriptorType(vk::DescriptorType::eUniformBuffer);
1627         writes[0].setPBufferInfo(&uniform_data.buffer_info);
1628 
1629         writes[1].setDstSet(desc_set);
1630         writes[1].setDstBinding(1);
1631         writes[1].setDescriptorCount(texture_count);
1632         writes[1].setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
1633         writes[1].setPImageInfo(tex_descs);
1634 
1635         device.updateDescriptorSets(2, writes, 0, nullptr);
1636     }
1637 
prepare_framebuffersDemo1638     void prepare_framebuffers() {
1639         vk::ImageView attachments[2];
1640         attachments[1] = depth.view;
1641 
1642         auto const fb_info = vk::FramebufferCreateInfo()
1643                                  .setRenderPass(render_pass)
1644                                  .setAttachmentCount(2)
1645                                  .setPAttachments(attachments)
1646                                  .setWidth((uint32_t)width)
1647                                  .setHeight((uint32_t)height)
1648                                  .setLayers(1);
1649 
1650         framebuffers.reset(new vk::Framebuffer[swapchainImageCount]);
1651 
1652         for (uint32_t i = 0; i < swapchainImageCount; i++) {
1653             attachments[0] = buffers[i].view;
1654             auto const result =
1655                 device.createFramebuffer(&fb_info, nullptr, &framebuffers[i]);
1656             VERIFY(result == vk::Result::eSuccess);
1657         }
1658     }
1659 
prepare_fsDemo1660     vk::ShaderModule prepare_fs() {
1661         size_t size = 0;
1662         void *fragShaderCode = read_spv("cube-frag.spv", &size);
1663 
1664         frag_shader_module = prepare_shader_module(fragShaderCode, size);
1665 
1666         free(fragShaderCode);
1667 
1668         return frag_shader_module;
1669     }
1670 
prepare_pipelineDemo1671     void prepare_pipeline() {
1672         vk::PipelineCacheCreateInfo const pipelineCacheInfo;
1673         auto result = device.createPipelineCache(&pipelineCacheInfo, nullptr,
1674                                                  &pipelineCache);
1675         VERIFY(result == vk::Result::eSuccess);
1676 
1677         vk::PipelineShaderStageCreateInfo const shaderStageInfo[2] = {
1678             vk::PipelineShaderStageCreateInfo()
1679                 .setStage(vk::ShaderStageFlagBits::eVertex)
1680                 .setModule(prepare_vs())
1681                 .setPName("main"),
1682             vk::PipelineShaderStageCreateInfo()
1683                 .setStage(vk::ShaderStageFlagBits::eFragment)
1684                 .setModule(prepare_fs())
1685                 .setPName("main")};
1686 
1687         vk::PipelineVertexInputStateCreateInfo const vertexInputInfo;
1688 
1689         auto const inputAssemblyInfo =
1690             vk::PipelineInputAssemblyStateCreateInfo().setTopology(
1691                 vk::PrimitiveTopology::eTriangleList);
1692 
1693         // TODO: Where are pViewports and pScissors set?
1694         auto const viewportInfo = vk::PipelineViewportStateCreateInfo()
1695                                       .setViewportCount(1)
1696                                       .setScissorCount(1);
1697 
1698         auto const rasterizationInfo =
1699             vk::PipelineRasterizationStateCreateInfo()
1700                 .setDepthClampEnable(VK_FALSE)
1701                 .setRasterizerDiscardEnable(VK_FALSE)
1702                 .setPolygonMode(vk::PolygonMode::eFill)
1703                 .setCullMode(vk::CullModeFlagBits::eBack)
1704                 .setFrontFace(vk::FrontFace::eCounterClockwise)
1705                 .setDepthBiasEnable(VK_FALSE)
1706                 .setLineWidth(1.0f);
1707 
1708         auto const multisampleInfo = vk::PipelineMultisampleStateCreateInfo();
1709 
1710         auto const stencilOp = vk::StencilOpState()
1711                                    .setFailOp(vk::StencilOp::eKeep)
1712                                    .setPassOp(vk::StencilOp::eKeep)
1713                                    .setCompareOp(vk::CompareOp::eAlways);
1714 
1715         auto const depthStencilInfo =
1716             vk::PipelineDepthStencilStateCreateInfo()
1717                 .setDepthTestEnable(VK_TRUE)
1718                 .setDepthWriteEnable(VK_TRUE)
1719                 .setDepthCompareOp(vk::CompareOp::eLessOrEqual)
1720                 .setDepthBoundsTestEnable(VK_FALSE)
1721                 .setStencilTestEnable(VK_FALSE)
1722                 .setFront(stencilOp)
1723                 .setBack(stencilOp);
1724 
1725         vk::PipelineColorBlendAttachmentState const colorBlendAttachments[1] = {
1726             vk::PipelineColorBlendAttachmentState().setColorWriteMask(
1727                 vk::ColorComponentFlagBits::eR |
1728                 vk::ColorComponentFlagBits::eG |
1729                 vk::ColorComponentFlagBits::eB |
1730                 vk::ColorComponentFlagBits::eA)};
1731 
1732         auto const colorBlendInfo = vk::PipelineColorBlendStateCreateInfo()
1733                                         .setAttachmentCount(1)
1734                                         .setPAttachments(colorBlendAttachments);
1735 
1736         vk::DynamicState const dynamicStates[2] = {vk::DynamicState::eViewport,
1737                                                    vk::DynamicState::eScissor};
1738 
1739         auto const dynamicStateInfo = vk::PipelineDynamicStateCreateInfo()
1740                                           .setPDynamicStates(dynamicStates)
1741                                           .setDynamicStateCount(2);
1742 
1743         auto const pipeline = vk::GraphicsPipelineCreateInfo()
1744                                   .setStageCount(2)
1745                                   .setPStages(shaderStageInfo)
1746                                   .setPVertexInputState(&vertexInputInfo)
1747                                   .setPInputAssemblyState(&inputAssemblyInfo)
1748                                   .setPViewportState(&viewportInfo)
1749                                   .setPRasterizationState(&rasterizationInfo)
1750                                   .setPMultisampleState(&multisampleInfo)
1751                                   .setPDepthStencilState(&depthStencilInfo)
1752                                   .setPColorBlendState(&colorBlendInfo)
1753                                   .setPDynamicState(&dynamicStateInfo)
1754                                   .setLayout(pipeline_layout)
1755                                   .setRenderPass(render_pass);
1756 
1757         result = device.createGraphicsPipelines(pipelineCache, 1, &pipeline,
1758                                                 nullptr, &this->pipeline);
1759         VERIFY(result == vk::Result::eSuccess);
1760 
1761         device.destroyShaderModule(frag_shader_module, nullptr);
1762         device.destroyShaderModule(vert_shader_module, nullptr);
1763     }
1764 
prepare_render_passDemo1765     void prepare_render_pass() {
1766         const vk::AttachmentDescription attachments[2] = {
1767             vk::AttachmentDescription()
1768                 .setFlags(vk::AttachmentDescriptionFlagBits::eMayAlias)
1769                 .setFormat(format)
1770                 .setSamples(vk::SampleCountFlagBits::e1)
1771                 .setLoadOp(vk::AttachmentLoadOp::eClear)
1772                 .setStoreOp(vk::AttachmentStoreOp::eStore)
1773                 .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
1774                 .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
1775                 .setInitialLayout(vk::ImageLayout::eColorAttachmentOptimal)
1776                 .setFinalLayout(vk::ImageLayout::ePresentSrcKHR),
1777             vk::AttachmentDescription()
1778                 .setFlags(vk::AttachmentDescriptionFlagBits::eMayAlias)
1779                 .setFormat(depth.format)
1780                 .setSamples(vk::SampleCountFlagBits::e1)
1781                 .setLoadOp(vk::AttachmentLoadOp::eClear)
1782                 .setStoreOp(vk::AttachmentStoreOp::eDontCare)
1783                 .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
1784                 .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
1785                 .setInitialLayout(
1786                     vk::ImageLayout::eDepthStencilAttachmentOptimal)
1787                 .setFinalLayout(
1788                     vk::ImageLayout::eDepthStencilAttachmentOptimal)};
1789 
1790         auto const color_reference =
1791             vk::AttachmentReference().setAttachment(0).setLayout(
1792                 vk::ImageLayout::eColorAttachmentOptimal);
1793 
1794         auto const depth_reference =
1795             vk::AttachmentReference().setAttachment(1).setLayout(
1796                 vk::ImageLayout::eDepthStencilAttachmentOptimal);
1797 
1798         auto const subpass =
1799             vk::SubpassDescription()
1800                 .setPipelineBindPoint(vk::PipelineBindPoint::eGraphics)
1801                 .setInputAttachmentCount(0)
1802                 .setPInputAttachments(nullptr)
1803                 .setColorAttachmentCount(1)
1804                 .setPColorAttachments(&color_reference)
1805                 .setPResolveAttachments(nullptr)
1806                 .setPDepthStencilAttachment(&depth_reference)
1807                 .setPreserveAttachmentCount(0)
1808                 .setPPreserveAttachments(nullptr);
1809 
1810         auto const rp_info = vk::RenderPassCreateInfo()
1811                                  .setAttachmentCount(2)
1812                                  .setPAttachments(attachments)
1813                                  .setSubpassCount(1)
1814                                  .setPSubpasses(&subpass)
1815                                  .setDependencyCount(0)
1816                                  .setPDependencies(nullptr);
1817 
1818         auto result = device.createRenderPass(&rp_info, nullptr, &render_pass);
1819         VERIFY(result == vk::Result::eSuccess);
1820     }
1821 
prepare_shader_moduleDemo1822     vk::ShaderModule prepare_shader_module(const void *code, size_t size) {
1823         auto const moduleCreateInfo =
1824             vk::ShaderModuleCreateInfo().setCodeSize(size).setPCode(
1825                 (uint32_t const *)code);
1826 
1827         vk::ShaderModule module;
1828         auto result =
1829             device.createShaderModule(&moduleCreateInfo, nullptr, &module);
1830         VERIFY(result == vk::Result::eSuccess);
1831 
1832         return module;
1833     }
1834 
prepare_texture_imageDemo1835     void prepare_texture_image(const char *filename, texture_object *tex_obj,
1836                                vk::ImageTiling tiling,
1837                                vk::ImageUsageFlags usage,
1838                                vk::MemoryPropertyFlags required_props) {
1839         int32_t tex_width;
1840         int32_t tex_height;
1841         if (!loadTexture(filename, nullptr, nullptr, &tex_width, &tex_height)) {
1842             ERR_EXIT("Failed to load textures", "Load Texture Failure");
1843         }
1844 
1845         tex_obj->tex_width = tex_width;
1846         tex_obj->tex_height = tex_height;
1847 
1848         auto const image_create_info =
1849             vk::ImageCreateInfo()
1850                 .setImageType(vk::ImageType::e2D)
1851                 .setFormat(vk::Format::eR8G8B8A8Unorm)
1852                 .setExtent({(uint32_t)tex_width, (uint32_t)tex_height, 1})
1853                 .setMipLevels(1)
1854                 .setArrayLayers(1)
1855                 .setSamples(vk::SampleCountFlagBits::e1)
1856                 .setTiling(tiling)
1857                 .setUsage(usage)
1858                 .setSharingMode(vk::SharingMode::eExclusive)
1859                 .setQueueFamilyIndexCount(0)
1860                 .setPQueueFamilyIndices(nullptr)
1861                 .setInitialLayout(vk::ImageLayout::ePreinitialized);
1862 
1863         auto result =
1864             device.createImage(&image_create_info, nullptr, &tex_obj->image);
1865         VERIFY(result == vk::Result::eSuccess);
1866 
1867         vk::MemoryRequirements mem_reqs;
1868         device.getImageMemoryRequirements(tex_obj->image, &mem_reqs);
1869 
1870         tex_obj->mem_alloc.setAllocationSize(mem_reqs.size);
1871         tex_obj->mem_alloc.setMemoryTypeIndex(0);
1872 
1873         auto pass =
1874             memory_type_from_properties(mem_reqs.memoryTypeBits, required_props,
1875                                         &tex_obj->mem_alloc.memoryTypeIndex);
1876         VERIFY(pass == true);
1877 
1878         result = device.allocateMemory(&tex_obj->mem_alloc, nullptr,
1879                                        &(tex_obj->mem));
1880         VERIFY(result == vk::Result::eSuccess);
1881 
1882         result = device.bindImageMemory(tex_obj->image, tex_obj->mem, 0);
1883         VERIFY(result == vk::Result::eSuccess);
1884 
1885         if (required_props & vk::MemoryPropertyFlagBits::eHostVisible) {
1886             auto const subres =
1887                 vk::ImageSubresource()
1888                     .setAspectMask(vk::ImageAspectFlagBits::eColor)
1889                     .setMipLevel(0)
1890                     .setArrayLayer(0);
1891             vk::SubresourceLayout layout;
1892             device.getImageSubresourceLayout(tex_obj->image, &subres, &layout);
1893 
1894             auto data = device.mapMemory(tex_obj->mem, 0,
1895                                          tex_obj->mem_alloc.allocationSize);
1896             VERIFY(data.result == vk::Result::eSuccess);
1897 
1898             if (!loadTexture(filename, (uint8_t *)data.value, &layout,
1899                              &tex_width, &tex_height)) {
1900                 fprintf(stderr, "Error loading texture: %s\n", filename);
1901             }
1902 
1903             device.unmapMemory(tex_obj->mem);
1904         }
1905 
1906         tex_obj->imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
1907         set_image_layout(tex_obj->image, vk::ImageAspectFlagBits::eColor,
1908                          vk::ImageLayout::ePreinitialized, tex_obj->imageLayout,
1909                          vk::AccessFlagBits::eHostWrite);
1910     }
1911 
prepare_texturesDemo1912     void prepare_textures() {
1913         vk::Format const tex_format = vk::Format::eR8G8B8A8Unorm;
1914         vk::FormatProperties props;
1915         gpu.getFormatProperties(tex_format, &props);
1916 
1917         for (uint32_t i = 0; i < texture_count; i++) {
1918             if ((props.linearTilingFeatures &
1919                  vk::FormatFeatureFlagBits::eSampledImage) &&
1920                 !use_staging_buffer) {
1921                 /* Device can texture using linear textures */
1922                 prepare_texture_image(
1923                     tex_files[i], &textures[i], vk::ImageTiling::eLinear,
1924                     vk::ImageUsageFlagBits::eSampled,
1925                     vk::MemoryPropertyFlagBits::eHostVisible |
1926                         vk::MemoryPropertyFlagBits::eHostCoherent);
1927             } else if (props.optimalTilingFeatures &
1928                        vk::FormatFeatureFlagBits::eSampledImage) {
1929                 /* Must use staging buffer to copy linear texture to optimized
1930                  */
1931                 texture_object staging_texture;
1932 
1933                 prepare_texture_image(
1934                     tex_files[i], &staging_texture, vk::ImageTiling::eLinear,
1935                     vk::ImageUsageFlagBits::eTransferSrc,
1936                     vk::MemoryPropertyFlagBits::eHostVisible |
1937                         vk::MemoryPropertyFlagBits::eHostCoherent);
1938 
1939                 prepare_texture_image(tex_files[i], &textures[i],
1940                                       vk::ImageTiling::eOptimal,
1941                                       vk::ImageUsageFlagBits::eTransferDst |
1942                                           vk::ImageUsageFlagBits::eSampled,
1943                                       vk::MemoryPropertyFlagBits::eDeviceLocal);
1944 
1945                 set_image_layout(
1946                     staging_texture.image, vk::ImageAspectFlagBits::eColor,
1947                     staging_texture.imageLayout,
1948                     vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlags());
1949 
1950                 set_image_layout(
1951                     textures[i].image, vk::ImageAspectFlagBits::eColor,
1952                     textures[i].imageLayout,
1953                     vk::ImageLayout::eTransferDstOptimal, vk::AccessFlags());
1954 
1955                 auto const subresource =
1956                     vk::ImageSubresourceLayers()
1957                         .setAspectMask(vk::ImageAspectFlagBits::eColor)
1958                         .setMipLevel(0)
1959                         .setBaseArrayLayer(0)
1960                         .setLayerCount(1);
1961 
1962                 auto const copy_region =
1963                     vk::ImageCopy()
1964                         .setSrcSubresource(subresource)
1965                         .setSrcOffset({0, 0, 0})
1966                         .setDstSubresource(subresource)
1967                         .setDstOffset({0, 0, 0})
1968                         .setExtent({(uint32_t)staging_texture.tex_width,
1969                                     (uint32_t)staging_texture.tex_height, 1});
1970 
1971                 cmd.copyImage(
1972                     staging_texture.image, vk::ImageLayout::eTransferSrcOptimal,
1973                     textures[i].image, vk::ImageLayout::eTransferDstOptimal, 1,
1974                     &copy_region);
1975 
1976                 set_image_layout(textures[i].image,
1977                                  vk::ImageAspectFlagBits::eColor,
1978                                  vk::ImageLayout::eTransferDstOptimal,
1979                                  textures[i].imageLayout, vk::AccessFlags());
1980 
1981                 flush_init_cmd();
1982 
1983                 destroy_texture_image(&staging_texture);
1984             } else {
1985                 assert(
1986                     !"No support for R8G8B8A8_UNORM as texture image format");
1987             }
1988 
1989             auto const samplerInfo =
1990                 vk::SamplerCreateInfo()
1991                     .setMagFilter(vk::Filter::eNearest)
1992                     .setMinFilter(vk::Filter::eNearest)
1993                     .setMipmapMode(vk::SamplerMipmapMode::eNearest)
1994                     .setAddressModeU(vk::SamplerAddressMode::eClampToEdge)
1995                     .setAddressModeV(vk::SamplerAddressMode::eClampToEdge)
1996                     .setAddressModeW(vk::SamplerAddressMode::eClampToEdge)
1997                     .setMipLodBias(0.0f)
1998                     .setAnisotropyEnable(VK_FALSE)
1999                     .setMaxAnisotropy(1)
2000                     .setCompareEnable(VK_FALSE)
2001                     .setCompareOp(vk::CompareOp::eNever)
2002                     .setMinLod(0.0f)
2003                     .setMaxLod(0.0f)
2004                     .setBorderColor(vk::BorderColor::eFloatOpaqueWhite)
2005                     .setUnnormalizedCoordinates(VK_FALSE);
2006 
2007             auto result = device.createSampler(&samplerInfo, nullptr,
2008                                                &textures[i].sampler);
2009             VERIFY(result == vk::Result::eSuccess);
2010 
2011             auto const viewInfo =
2012                 vk::ImageViewCreateInfo()
2013                     .setImage(textures[i].image)
2014                     .setViewType(vk::ImageViewType::e2D)
2015                     .setFormat(tex_format)
2016                     .setSubresourceRange(vk::ImageSubresourceRange(
2017                         vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
2018 
2019             result =
2020                 device.createImageView(&viewInfo, nullptr, &textures[i].view);
2021             VERIFY(result == vk::Result::eSuccess);
2022         }
2023     }
2024 
prepare_vsDemo2025     vk::ShaderModule prepare_vs() {
2026         size_t size = 0;
2027         void *vertShaderCode = read_spv("cube-vert.spv", &size);
2028 
2029         vert_shader_module = prepare_shader_module(vertShaderCode, size);
2030 
2031         free(vertShaderCode);
2032 
2033         return vert_shader_module;
2034     }
2035 
read_spvDemo2036     char *read_spv(const char *filename, size_t *psize) {
2037         FILE *fp = fopen(filename, "rb");
2038         if (!fp) {
2039             return nullptr;
2040         }
2041 
2042         fseek(fp, 0L, SEEK_END);
2043         long int size = ftell(fp);
2044 
2045         fseek(fp, 0L, SEEK_SET);
2046 
2047         void *shader_code = malloc(size);
2048         size_t retval = fread(shader_code, size, 1, fp);
2049         VERIFY(retval == 1);
2050 
2051         *psize = size;
2052 
2053         fclose(fp);
2054 
2055         return (char *)shader_code;
2056     }
2057 
resizeDemo2058     void resize() {
2059         uint32_t i;
2060 
2061         // Don't react to resize until after first initialization.
2062         if (!prepared) {
2063             return;
2064         }
2065 
2066         // In order to properly resize the window, we must re-create the
2067         // swapchain
2068         // AND redo the command buffers, etc.
2069         //
2070         // First, perform part of the cleanup() function:
2071         prepared = false;
2072         auto result = device.waitIdle();
2073         VERIFY(result == vk::Result::eSuccess);
2074 
2075         for (i = 0; i < swapchainImageCount; i++) {
2076             device.destroyFramebuffer(framebuffers[i], nullptr);
2077         }
2078 
2079         device.destroyDescriptorPool(desc_pool, nullptr);
2080 
2081         device.destroyPipeline(pipeline, nullptr);
2082         device.destroyPipelineCache(pipelineCache, nullptr);
2083         device.destroyRenderPass(render_pass, nullptr);
2084         device.destroyPipelineLayout(pipeline_layout, nullptr);
2085         device.destroyDescriptorSetLayout(desc_layout, nullptr);
2086 
2087         for (i = 0; i < texture_count; i++) {
2088             device.destroyImageView(textures[i].view, nullptr);
2089             device.destroyImage(textures[i].image, nullptr);
2090             device.freeMemory(textures[i].mem, nullptr);
2091             device.destroySampler(textures[i].sampler, nullptr);
2092         }
2093 
2094         device.destroyImageView(depth.view, nullptr);
2095         device.destroyImage(depth.image, nullptr);
2096         device.freeMemory(depth.mem, nullptr);
2097 
2098         device.destroyBuffer(uniform_data.buf, nullptr);
2099         device.freeMemory(uniform_data.mem, nullptr);
2100 
2101         for (i = 0; i < swapchainImageCount; i++) {
2102             device.destroyImageView(buffers[i].view, nullptr);
2103             device.freeCommandBuffers(cmd_pool, 1, &buffers[i].cmd);
2104         }
2105 
2106         device.destroyCommandPool(cmd_pool, nullptr);
2107         if (separate_present_queue) {
2108             device.destroyCommandPool(present_cmd_pool, nullptr);
2109         }
2110 
2111         // Second, re-perform the prepare() function, which will re-create the
2112         // swapchain.
2113         prepare();
2114     }
2115 
set_image_layoutDemo2116     void set_image_layout(vk::Image image, vk::ImageAspectFlags aspectMask,
2117                           vk::ImageLayout oldLayout, vk::ImageLayout newLayout,
2118                           vk::AccessFlags srcAccessMask) {
2119         if (!cmd) {
2120             auto const cmd = vk::CommandBufferAllocateInfo()
2121                                  .setCommandPool(cmd_pool)
2122                                  .setLevel(vk::CommandBufferLevel::ePrimary)
2123                                  .setCommandBufferCount(1);
2124 
2125             auto result = device.allocateCommandBuffers(&cmd, &this->cmd);
2126             VERIFY(result == vk::Result::eSuccess);
2127 
2128             auto const cmd_buf_info =
2129                 vk::CommandBufferBeginInfo().setPInheritanceInfo(nullptr);
2130 
2131             result = this->cmd.begin(&cmd_buf_info);
2132             VERIFY(result == vk::Result::eSuccess);
2133         }
2134 
2135         auto DstAccessMask = [](vk::ImageLayout const &layout) {
2136             vk::AccessFlags flags;
2137 
2138             switch (layout) {
2139             case vk::ImageLayout::eTransferDstOptimal:
2140                 // Make sure anything that was copying from this image has
2141                 // completed
2142                 flags = vk::AccessFlagBits::eTransferRead;
2143                 break;
2144             case vk::ImageLayout::eColorAttachmentOptimal:
2145                 flags = vk::AccessFlagBits::eColorAttachmentWrite;
2146                 break;
2147             case vk::ImageLayout::eDepthStencilAttachmentOptimal:
2148                 flags = vk::AccessFlagBits::eDepthStencilAttachmentWrite;
2149                 break;
2150             case vk::ImageLayout::eShaderReadOnlyOptimal:
2151                 // Make sure any Copy or CPU writes to image are flushed
2152                 flags = vk::AccessFlagBits::eShaderRead |
2153                         vk::AccessFlagBits::eInputAttachmentRead;
2154                 break;
2155             case vk::ImageLayout::ePresentSrcKHR:
2156                 flags = vk::AccessFlagBits::eMemoryRead;
2157                 break;
2158             default:
2159                 break;
2160             }
2161 
2162             return flags;
2163         };
2164 
2165         auto const barrier = vk::ImageMemoryBarrier()
2166                                  .setSrcAccessMask(srcAccessMask)
2167                                  .setDstAccessMask(DstAccessMask(newLayout))
2168                                  .setOldLayout(oldLayout)
2169                                  .setNewLayout(newLayout)
2170                                  .setSrcQueueFamilyIndex(0)
2171                                  .setDstQueueFamilyIndex(0)
2172                                  .setImage(image)
2173                                  .setSubresourceRange(vk::ImageSubresourceRange(
2174                                      aspectMask, 0, 1, 0, 1));
2175 
2176         cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe,
2177                             vk::PipelineStageFlagBits::eTopOfPipe,
2178                             vk::DependencyFlagBits(), 0, nullptr, 0, nullptr, 1,
2179                             &barrier);
2180     }
2181 
update_data_bufferDemo2182     void update_data_buffer() {
2183         mat4x4 VP;
2184         mat4x4_mul(VP, projection_matrix, view_matrix);
2185 
2186         // Rotate 22.5 degrees around the Y axis
2187         mat4x4 Model;
2188         mat4x4_dup(Model, model_matrix);
2189         mat4x4_rotate(model_matrix, Model, 0.0f, 1.0f, 0.0f,
2190                       (float)degreesToRadians(spin_angle));
2191 
2192         mat4x4 MVP;
2193         mat4x4_mul(MVP, VP, model_matrix);
2194 
2195         auto data = device.mapMemory(uniform_data.mem, 0,
2196                                      uniform_data.mem_alloc.allocationSize,
2197                                      vk::MemoryMapFlags());
2198         VERIFY(data.result == vk::Result::eSuccess);
2199 
2200         memcpy(data.value, (const void *)&MVP[0][0], sizeof(MVP));
2201 
2202         device.unmapMemory(uniform_data.mem);
2203     }
2204 
loadTextureDemo2205     bool loadTexture(const char *filename, uint8_t *rgba_data,
2206                      vk::SubresourceLayout *layout, int32_t *width,
2207                      int32_t *height) {
2208         FILE *fPtr = fopen(filename, "rb");
2209         if (!fPtr) {
2210             return false;
2211         }
2212 
2213         char header[256];
2214         char *cPtr = fgets(header, 256, fPtr); // P6
2215         if (cPtr == nullptr || strncmp(header, "P6\n", 3)) {
2216             fclose(fPtr);
2217             return false;
2218         }
2219 
2220         do {
2221             cPtr = fgets(header, 256, fPtr);
2222             if (cPtr == nullptr) {
2223                 fclose(fPtr);
2224                 return false;
2225             }
2226         } while (!strncmp(header, "#", 1));
2227 
2228         sscanf(header, "%u %u", width, height);
2229         if (rgba_data == nullptr) {
2230             fclose(fPtr);
2231             return true;
2232         }
2233 
2234         char *result = fgets(header, 256, fPtr); // Format
2235         VERIFY(result != nullptr);
2236         if (cPtr == nullptr || strncmp(header, "255\n", 3)) {
2237             fclose(fPtr);
2238             return false;
2239         }
2240 
2241         for (int y = 0; y < *height; y++) {
2242             uint8_t *rowPtr = rgba_data;
2243 
2244             for (int x = 0; x < *width; x++) {
2245                 size_t s = fread(rowPtr, 3, 1, fPtr);
2246                 (void)s;
2247                 rowPtr[3] = 255; /* Alpha of 1 */
2248                 rowPtr += 4;
2249             }
2250 
2251             rgba_data += layout->rowPitch;
2252         }
2253 
2254         fclose(fPtr);
2255         return true;
2256     }
2257 
memory_type_from_propertiesDemo2258     bool memory_type_from_properties(uint32_t typeBits,
2259                                      vk::MemoryPropertyFlags requirements_mask,
2260                                      uint32_t *typeIndex) {
2261         // Search memtypes to find first index with those properties
2262         for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
2263             if ((typeBits & 1) == 1) {
2264                 // Type is available, does it match user properties?
2265                 if ((memory_properties.memoryTypes[i].propertyFlags &
2266                      requirements_mask) == requirements_mask) {
2267                     *typeIndex = i;
2268                     return true;
2269                 }
2270             }
2271             typeBits >>= 1;
2272         }
2273 
2274         // No memory types matched, return failure
2275         return false;
2276     }
2277 
2278 #if defined(VK_USE_PLATFORM_WIN32_KHR)
runDemo2279     void run() {
2280         if (!prepared) {
2281             return;
2282         }
2283 
2284         update_data_buffer();
2285         draw();
2286         curFrame++;
2287 
2288         if (frameCount != INT_MAX && curFrame == frameCount) {
2289             PostQuitMessage(validation_error);
2290         }
2291     }
2292 
create_windowDemo2293     void create_window() {
2294         WNDCLASSEX win_class;
2295 
2296         // Initialize the window class structure:
2297         win_class.cbSize = sizeof(WNDCLASSEX);
2298         win_class.style = CS_HREDRAW | CS_VREDRAW;
2299         win_class.lpfnWndProc = WndProc;
2300         win_class.cbClsExtra = 0;
2301         win_class.cbWndExtra = 0;
2302         win_class.hInstance = connection; // hInstance
2303         win_class.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
2304         win_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
2305         win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
2306         win_class.lpszMenuName = nullptr;
2307         win_class.lpszClassName = name;
2308         win_class.hIconSm = LoadIcon(nullptr, IDI_WINLOGO);
2309 
2310         // Register window class:
2311         if (!RegisterClassEx(&win_class)) {
2312             // It didn't work, so try to give a useful error:
2313             printf("Unexpected error trying to start the application!\n");
2314             fflush(stdout);
2315             exit(1);
2316         }
2317 
2318         // Create window with the registered class:
2319         RECT wr = {0, 0, static_cast<LONG>(width), static_cast<LONG>(height)};
2320         AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
2321         window = CreateWindowEx(0,
2322                                 name,                 // class name
2323                                 name,                 // app name
2324                                 WS_OVERLAPPEDWINDOW | // window style
2325                                     WS_VISIBLE | WS_SYSMENU,
2326                                 100, 100,           // x/y coords
2327                                 wr.right - wr.left, // width
2328                                 wr.bottom - wr.top, // height
2329                                 nullptr,            // handle to parent
2330                                 nullptr,            // handle to menu
2331                                 connection,         // hInstance
2332                                 nullptr);           // no extra parameters
2333 
2334         if (!window) {
2335             // It didn't work, so try to give a useful error:
2336             printf("Cannot create a window in which to draw!\n");
2337             fflush(stdout);
2338             exit(1);
2339         }
2340 
2341         // Window client area size must be at least 1 pixel high, to prevent
2342         // crash.
2343         minsize.x = GetSystemMetrics(SM_CXMINTRACK);
2344         minsize.y = GetSystemMetrics(SM_CYMINTRACK) + 1;
2345     }
2346 
2347 #elif defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
2348 #if defined(VK_USE_PLATFORM_XLIB_KHR)
2349 
create_xlib_windowDemo2350     void create_xlib_window() {
2351         display = XOpenDisplay(nullptr);
2352         long visualMask = VisualScreenMask;
2353         int numberOfVisuals;
2354         XVisualInfo vInfoTemplate = {};
2355         vInfoTemplate.screen = DefaultScreen(display);
2356         XVisualInfo *visualInfo = XGetVisualInfo(
2357             display, visualMask, &vInfoTemplate, &numberOfVisuals);
2358 
2359         Colormap colormap =
2360             XCreateColormap(display, RootWindow(display, vInfoTemplate.screen),
2361                             visualInfo->visual, AllocNone);
2362 
2363         XSetWindowAttributes windowAttributes = {};
2364         windowAttributes.colormap = colormap;
2365         windowAttributes.background_pixel = 0xFFFFFFFF;
2366         windowAttributes.border_pixel = 0;
2367         windowAttributes.event_mask =
2368             KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask;
2369 
2370         xlib_window = XCreateWindow(
2371             display, RootWindow(display, vInfoTemplate.screen), 0, 0, width,
2372             height, 0, visualInfo->depth, InputOutput, visualInfo->visual,
2373             CWBackPixel | CWBorderPixel | CWEventMask | CWColormap,
2374             &windowAttributes);
2375 
2376         XSelectInput(display, xlib_window, ExposureMask | KeyPressMask);
2377         XMapWindow(display, xlib_window);
2378         XFlush(display);
2379         xlib_wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
2380     }
2381 
handle_xlib_eventDemo2382     void handle_xlib_event(const XEvent *event) {
2383         switch (event->type) {
2384         case ClientMessage:
2385             if ((Atom)event->xclient.data.l[0] == xlib_wm_delete_window) {
2386                 quit = true;
2387             }
2388             break;
2389         case KeyPress:
2390             switch (event->xkey.keycode) {
2391             case 0x9: // Escape
2392                 quit = true;
2393                 break;
2394             case 0x71: // left arrow key
2395                 spin_angle += spin_increment;
2396                 break;
2397             case 0x72: // right arrow key
2398                 spin_angle -= spin_increment;
2399                 break;
2400             case 0x41:
2401                 pause = !pause;
2402                 break;
2403             }
2404             break;
2405         case ConfigureNotify:
2406             if (((int32_t)width != event->xconfigure.width) ||
2407                 ((int32_t)height != event->xconfigure.height)) {
2408                 width = event->xconfigure.width;
2409                 height = event->xconfigure.height;
2410                 resize();
2411             }
2412             break;
2413         default:
2414             break;
2415         }
2416     }
2417 
run_xlibDemo2418     void run_xlib() {
2419         while (!quit) {
2420             XEvent event;
2421 
2422             if (pause) {
2423                 XNextEvent(display, &event);
2424                 handle_xlib_event(&event);
2425             } else {
2426                 while (XPending(display) > 0) {
2427                     XNextEvent(display, &event);
2428                     handle_xlib_event(&event);
2429                 }
2430             }
2431 
2432             update_data_buffer();
2433             draw();
2434             curFrame++;
2435 
2436             if (frameCount != UINT32_MAX && curFrame == frameCount) {
2437                 quit = true;
2438             }
2439         }
2440     }
2441 
2442 #endif
2443 #if defined(VK_USE_PLATFORM_XCB_KHR)
2444 
handle_xcb_eventDemo2445     void handle_xcb_event(const xcb_generic_event_t *event) {
2446         uint8_t event_code = event->response_type & 0x7f;
2447         switch (event_code) {
2448         case XCB_EXPOSE:
2449             // TODO: Resize window
2450             break;
2451         case XCB_CLIENT_MESSAGE:
2452             if ((*(xcb_client_message_event_t *)event).data.data32[0] ==
2453                 (*atom_wm_delete_window).atom) {
2454                 quit = true;
2455             }
2456             break;
2457         case XCB_KEY_RELEASE: {
2458             const xcb_key_release_event_t *key =
2459                 (const xcb_key_release_event_t *)event;
2460 
2461             switch (key->detail) {
2462             case 0x9: // Escape
2463                 quit = true;
2464                 break;
2465             case 0x71: // left arrow key
2466                 spin_angle += spin_increment;
2467                 break;
2468             case 0x72: // right arrow key
2469                 spin_angle -= spin_increment;
2470                 break;
2471             case 0x41:
2472                 pause = !pause;
2473                 break;
2474             }
2475         } break;
2476         case XCB_CONFIGURE_NOTIFY: {
2477             const xcb_configure_notify_event_t *cfg =
2478                 (const xcb_configure_notify_event_t *)event;
2479             if ((width != cfg->width) || (height != cfg->height)) {
2480                 width = cfg->width;
2481                 height = cfg->height;
2482                 resize();
2483             }
2484         } break;
2485         default:
2486             break;
2487         }
2488     }
2489 
run_xcbDemo2490     void run_xcb() {
2491         xcb_flush(connection);
2492 
2493         while (!quit) {
2494             xcb_generic_event_t *event;
2495 
2496             if (pause) {
2497                 event = xcb_wait_for_event(connection);
2498             } else {
2499                 event = xcb_poll_for_event(connection);
2500                 while (event) {
2501                     handle_xcb_event(event);
2502                     free(event);
2503                     event = xcb_poll_for_event(connection);
2504                 }
2505             }
2506 
2507             update_data_buffer();
2508             draw();
2509             curFrame++;
2510             if (frameCount != UINT32_MAX && curFrame == frameCount) {
2511                 quit = true;
2512             }
2513         }
2514     }
2515 
create_xcb_windowDemo2516     void create_xcb_window() {
2517         uint32_t value_mask, value_list[32];
2518 
2519         xcb_window = xcb_generate_id(connection);
2520 
2521         value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
2522         value_list[0] = screen->black_pixel;
2523         value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE |
2524                         XCB_EVENT_MASK_STRUCTURE_NOTIFY;
2525 
2526         xcb_create_window(connection, XCB_COPY_FROM_PARENT, xcb_window,
2527                           screen->root, 0, 0, width, height, 0,
2528                           XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual,
2529                           value_mask, value_list);
2530 
2531         /* Magic code that will send notification when window is destroyed */
2532         xcb_intern_atom_cookie_t cookie =
2533             xcb_intern_atom(connection, 1, 12, "WM_PROTOCOLS");
2534         xcb_intern_atom_reply_t *reply =
2535             xcb_intern_atom_reply(connection, cookie, 0);
2536 
2537         xcb_intern_atom_cookie_t cookie2 =
2538             xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW");
2539         atom_wm_delete_window = xcb_intern_atom_reply(connection, cookie2, 0);
2540 
2541         xcb_change_property(connection, XCB_PROP_MODE_REPLACE, xcb_window,
2542                             (*reply).atom, 4, 32, 1,
2543                             &(*atom_wm_delete_window).atom);
2544 
2545         free(reply);
2546 
2547         xcb_map_window(connection, xcb_window);
2548 
2549         // Force the x/y coordinates to 100,100 results are identical in
2550         // consecutive
2551         // runs
2552         const uint32_t coords[] = {100, 100};
2553         xcb_configure_window(connection, xcb_window,
2554                              XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
2555     }
2556 
2557 #endif
2558 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
2559 
runDemo2560     void run() {
2561         while (!quit) {
2562             update_data_buffer();
2563             draw();
2564             curFrame++;
2565             if (frameCount != UINT32_MAX && curFrame == frameCount) {
2566                 quit = true;
2567             }
2568         }
2569     }
2570 
create_windowDemo2571     void create_window() {
2572         window = wl_compositor_create_surface(compositor);
2573         if (!window) {
2574             printf("Can not create wayland_surface from compositor!\n");
2575             fflush(stdout);
2576             exit(1);
2577         }
2578 
2579         shell_surface = wl_shell_get_shell_surface(shell, window);
2580         if (!shell_surface) {
2581             printf("Can not get shell_surface from wayland_surface!\n");
2582             fflush(stdout);
2583             exit(1);
2584         }
2585 
2586         wl_shell_surface_add_listener(shell_surface, &shell_surface_listener,
2587                                       this);
2588         wl_shell_surface_set_toplevel(shell_surface);
2589         wl_shell_surface_set_title(shell_surface, APP_SHORT_NAME);
2590     }
2591 
2592 #endif
2593 
2594 #if defined(VK_USE_PLATFORM_WIN32_KHR)
2595     HINSTANCE connection;        // hInstance - Windows Instance
2596     HWND window;                 // hWnd - window handle
2597     POINT minsize;               // minimum window size
2598     char name[APP_NAME_STR_LEN]; // Name to put on the window/icon
2599 #elif defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
2600     Display *display;
2601     Window xlib_window;
2602     Atom xlib_wm_delete_window;
2603 
2604     xcb_connection_t *connection;
2605     xcb_screen_t *screen;
2606     xcb_window_t xcb_window;
2607     xcb_intern_atom_reply_t *atom_wm_delete_window;
2608 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
2609     wl_display *display;
2610     wl_registry *registry;
2611     wl_compositor *compositor;
2612     wl_surface *window;
2613     wl_shell *shell;
2614     wl_shell_surface *shell_surface;
2615 #endif
2616 
2617     vk::SurfaceKHR surface;
2618     bool prepared;
2619     bool use_staging_buffer;
2620     bool use_xlib;
2621     bool separate_present_queue;
2622 
2623     vk::Instance inst;
2624     vk::PhysicalDevice gpu;
2625     vk::Device device;
2626     vk::Queue graphics_queue;
2627     vk::Queue present_queue;
2628     uint32_t graphics_queue_family_index;
2629     uint32_t present_queue_family_index;
2630     vk::Semaphore image_acquired_semaphores[FRAME_LAG];
2631     vk::Semaphore draw_complete_semaphores[FRAME_LAG];
2632     vk::Semaphore image_ownership_semaphores[FRAME_LAG];
2633     vk::PhysicalDeviceProperties gpu_props;
2634     std::unique_ptr<vk::QueueFamilyProperties[]> queue_props;
2635     vk::PhysicalDeviceMemoryProperties memory_properties;
2636 
2637     uint32_t enabled_extension_count;
2638     uint32_t enabled_layer_count;
2639     char const *extension_names[64];
2640     char const *enabled_layers[64];
2641 
2642     uint32_t width;
2643     uint32_t height;
2644     vk::Format format;
2645     vk::ColorSpaceKHR color_space;
2646 
2647     uint32_t swapchainImageCount;
2648     vk::SwapchainKHR swapchain;
2649     std::unique_ptr<SwapchainBuffers[]> buffers;
2650     vk::Fence fences[FRAME_LAG];
2651     bool fencesInited[FRAME_LAG];
2652     uint32_t frame_index;
2653 
2654     vk::CommandPool cmd_pool;
2655     vk::CommandPool present_cmd_pool;
2656 
2657     struct {
2658         vk::Format format;
2659         vk::Image image;
2660         vk::MemoryAllocateInfo mem_alloc;
2661         vk::DeviceMemory mem;
2662         vk::ImageView view;
2663     } depth;
2664 
2665     static int32_t const texture_count = 1;
2666     texture_object textures[texture_count];
2667 
2668     struct {
2669         vk::Buffer buf;
2670         vk::MemoryAllocateInfo mem_alloc;
2671         vk::DeviceMemory mem;
2672         vk::DescriptorBufferInfo buffer_info;
2673     } uniform_data;
2674 
2675     vk::CommandBuffer cmd; // Buffer for initialization commands
2676     vk::PipelineLayout pipeline_layout;
2677     vk::DescriptorSetLayout desc_layout;
2678     vk::PipelineCache pipelineCache;
2679     vk::RenderPass render_pass;
2680     vk::Pipeline pipeline;
2681 
2682     mat4x4 projection_matrix;
2683     mat4x4 view_matrix;
2684     mat4x4 model_matrix;
2685 
2686     float spin_angle;
2687     float spin_increment;
2688     bool pause;
2689 
2690     vk::ShaderModule vert_shader_module;
2691     vk::ShaderModule frag_shader_module;
2692 
2693     vk::DescriptorPool desc_pool;
2694     vk::DescriptorSet desc_set;
2695 
2696     std::unique_ptr<vk::Framebuffer[]> framebuffers;
2697 
2698     bool quit;
2699     uint32_t curFrame;
2700     uint32_t frameCount;
2701     bool validate;
2702     bool use_break;
2703     bool suppress_popups;
2704 
2705     uint32_t current_buffer;
2706     uint32_t queue_family_count;
2707 };
2708 
2709 #if _WIN32
2710 // Include header required for parsing the command line options.
2711 #include <shellapi.h>
2712 
2713 Demo demo;
2714 
2715 // MS-Windows event handling function:
WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2716 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
2717     switch (uMsg) {
2718     case WM_CLOSE:
2719         PostQuitMessage(validation_error);
2720         break;
2721     case WM_PAINT:
2722         demo.run();
2723         break;
2724     case WM_GETMINMAXINFO: // set window's minimum size
2725         ((MINMAXINFO *)lParam)->ptMinTrackSize = demo.minsize;
2726         return 0;
2727     case WM_SIZE:
2728         // Resize the application to the new window size, except when
2729         // it was minimized. Vulkan doesn't support images or swapchains
2730         // with width=0 and height=0.
2731         if (wParam != SIZE_MINIMIZED) {
2732             demo.width = lParam & 0xffff;
2733             demo.height = (lParam & 0xffff0000) >> 16;
2734             demo.resize();
2735         }
2736         break;
2737     default:
2738         break;
2739     }
2740 
2741     return (DefWindowProc(hWnd, uMsg, wParam, lParam));
2742 }
2743 
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR pCmdLine,int nCmdShow)2744 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine,
2745                    int nCmdShow) {
2746     // TODO: Gah.. refactor. This isn't 1989.
2747     MSG msg;   // message
2748     bool done; // flag saying when app is complete
2749     int argc;
2750     char **argv;
2751 
2752     // Use the CommandLine functions to get the command line arguments.
2753     // Unfortunately, Microsoft outputs
2754     // this information as wide characters for Unicode, and we simply want the
2755     // Ascii version to be compatible
2756     // with the non-Windows side.  So, we have to convert the information to
2757     // Ascii character strings.
2758     LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc);
2759     if (nullptr == commandLineArgs) {
2760         argc = 0;
2761     }
2762 
2763     if (argc > 0) {
2764         argv = (char **)malloc(sizeof(char *) * argc);
2765         if (argv == nullptr) {
2766             argc = 0;
2767         } else {
2768             for (int iii = 0; iii < argc; iii++) {
2769                 size_t wideCharLen = wcslen(commandLineArgs[iii]);
2770                 size_t numConverted = 0;
2771 
2772                 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1));
2773                 if (argv[iii] != nullptr) {
2774                     wcstombs_s(&numConverted, argv[iii], wideCharLen + 1,
2775                                commandLineArgs[iii], wideCharLen + 1);
2776                 }
2777             }
2778         }
2779     } else {
2780         argv = nullptr;
2781     }
2782 
2783     demo.init(argc, argv);
2784 
2785     // Free up the items we had to allocate for the command line arguments.
2786     if (argc > 0 && argv != nullptr) {
2787         for (int iii = 0; iii < argc; iii++) {
2788             if (argv[iii] != nullptr) {
2789                 free(argv[iii]);
2790             }
2791         }
2792         free(argv);
2793     }
2794 
2795     demo.connection = hInstance;
2796     strncpy(demo.name, "cube", APP_NAME_STR_LEN);
2797     demo.create_window();
2798     demo.init_vk_swapchain();
2799 
2800     demo.prepare();
2801 
2802     done = false; // initialize loop condition variable
2803 
2804     // main message loop
2805     while (!done) {
2806         PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE);
2807         if (msg.message == WM_QUIT) // check for a quit message
2808         {
2809             done = true; // if found, quit app
2810         } else {
2811             /* Translate and dispatch to event queue*/
2812             TranslateMessage(&msg);
2813             DispatchMessage(&msg);
2814         }
2815         RedrawWindow(demo.window, nullptr, nullptr, RDW_INTERNALPAINT);
2816     }
2817 
2818     demo.cleanup();
2819 
2820     return (int)msg.wParam;
2821 }
2822 
2823 #elif __linux__
2824 
2825 #if defined(VK_USE_PLATFORM_WAYLAND_KHR)
handle_ping(void * data,wl_shell_surface * shell_surface,uint32_t serial)2826 static void handle_ping(void *data, wl_shell_surface *shell_surface,
2827                         uint32_t serial) {
2828     wl_shell_surface_pong(shell_surface, serial);
2829 }
2830 
handle_configure(void * data,wl_shell_surface * shell_surface,uint32_t edges,int32_t width,int32_t height)2831 static void handle_configure(void *data,
2832                              wl_shell_surface *shell_surface,
2833                              uint32_t edges, int32_t width,
2834                              int32_t height) {}
2835 
handle_popup_done(void * data,wl_shell_surface * shell_surface)2836 static void handle_popup_done(void *data,
2837                               wl_shell_surface *shell_surface) {}
2838 
2839 static const wl_shell_surface_listener shell_surface_listener = {
2840     handle_ping, handle_configure, handle_popup_done};
2841 #endif
2842 
main(int argc,char ** argv)2843 int main(int argc, char **argv) {
2844     Demo demo;
2845 
2846     demo.init(argc, argv);
2847 
2848 #if defined(VK_USE_PLATFORM_XLIB_KHR) && defined(VK_USE_PLATFORM_XCB_KHR)
2849     if (demo.use_xlib) {
2850         demo.create_xlib_window();
2851     } else {
2852         demo.create_xcb_window();
2853 #elif defined(VK_USE_PLATFORM_XCB_KHR)
2854     demo.create_xcb_window();
2855 #elif defined(VK_USE_PLATFORM_XLIB_KHR)
2856     demo.create_xlib_window();
2857 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
2858     demo.create_window();
2859 #endif
2860     }
2861 
2862     demo.init_vk_swapchain();
2863 
2864     demo.prepare();
2865 
2866 #if defined(VK_USE_PLATFORM_XLIB_KHR) && defined(VK_USE_PLATFORM_XCB_KHR)
2867     if (demo.use_xlib) {
2868         demo.run_xlib();
2869     } else {
2870         demo.run_xcb();
2871 #elif defined(VK_USE_PLATFORM_XCB_KHR)
2872 demo.run_xcb();
2873 #elif defined(VK_USE_PLATFORM_XLIB_KHR)
2874 demo.run_xlib();
2875 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
2876 demo.run();
2877 #endif
2878     }
2879 
2880     demo.cleanup();
2881 
2882     return validation_error;
2883 }
2884 
2885 #else
2886 #error "Platform not supported"
2887 #endif
2888