blob: 4d9c7224b6a62841ae880d13f17fe8c269a04cdb [file] [log] [blame]
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001/*
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
Tony Barbourefd0c5a2016-12-07 14:45:12 -070032#if defined(VK_USE_PLATFORM_MIR_KHR)
33#warning "Cubepp does not have code for Mir at this time"
34#endif
35
Jeremy Hayesf56427a2016-09-07 15:55:11 -060036#define VULKAN_HPP_NO_EXCEPTIONS
37#include <vulkan/vulkan.hpp>
38#include <vulkan/vk_sdk_platform.h>
39
40#include "linmath.h"
41
42#ifndef NDEBUG
43#define VERIFY(x) assert(x)
44#else
45#define VERIFY(x) ((void)(x))
46#endif
47
48#define APP_SHORT_NAME "cube"
49#ifdef _WIN32
50#define APP_NAME_STR_LEN 80
51#endif
52
53// Allow a maximum of two outstanding presentation operations.
54#define FRAME_LAG 2
55
56#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
57
58#ifdef _WIN32
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -070059#define ERR_EXIT(err_msg, err_class) \
60 do { \
61 if (!suppress_popups) \
62 MessageBox(nullptr, err_msg, err_class, MB_OK); \
63 exit(1); \
Jeremy Hayesf56427a2016-09-07 15:55:11 -060064 } while (0)
65#else
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -070066#define ERR_EXIT(err_msg, err_class) \
67 do { \
68 printf(err_msg); \
69 fflush(stdout); \
70 exit(1); \
Jeremy Hayesf56427a2016-09-07 15:55:11 -060071 } while (0)
72#endif
73
Jeremy Hayes9d304782016-10-09 11:48:12 -060074struct texture_object {
Jeremy Hayesf56427a2016-09-07 15:55:11 -060075 vk::Sampler sampler;
76
77 vk::Image image;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -070078 vk::ImageLayout imageLayout{vk::ImageLayout::eUndefined};
Jeremy Hayesf56427a2016-09-07 15:55:11 -060079
80 vk::MemoryAllocateInfo mem_alloc;
81 vk::DeviceMemory mem;
82 vk::ImageView view;
83
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -070084 int32_t tex_width{0};
85 int32_t tex_height{0};
Jeremy Hayesf56427a2016-09-07 15:55:11 -060086};
87
Jeremy Hayes9d304782016-10-09 11:48:12 -060088static char const *const tex_files[] = {"lunarg.ppm"};
Jeremy Hayesf56427a2016-09-07 15:55:11 -060089
90static int validation_error = 0;
91
92struct vkcube_vs_uniform {
93 // Must start with MVP
94 float mvp[4][4];
95 float position[12 * 3][4];
96 float color[12 * 3][4];
97};
98
99struct vktexcube_vs_uniform {
100 // Must start with MVP
101 float mvp[4][4];
102 float position[12 * 3][4];
103 float attr[12 * 3][4];
104};
105
106//--------------------------------------------------------------------------------------
107// Mesh and VertexFormat Data
108//--------------------------------------------------------------------------------------
109// clang-format off
110static const float g_vertex_buffer_data[] = {
111 -1.0f,-1.0f,-1.0f, // -X side
112 -1.0f,-1.0f, 1.0f,
113 -1.0f, 1.0f, 1.0f,
114 -1.0f, 1.0f, 1.0f,
115 -1.0f, 1.0f,-1.0f,
116 -1.0f,-1.0f,-1.0f,
117
118 -1.0f,-1.0f,-1.0f, // -Z side
119 1.0f, 1.0f,-1.0f,
120 1.0f,-1.0f,-1.0f,
121 -1.0f,-1.0f,-1.0f,
122 -1.0f, 1.0f,-1.0f,
123 1.0f, 1.0f,-1.0f,
124
125 -1.0f,-1.0f,-1.0f, // -Y side
126 1.0f,-1.0f,-1.0f,
127 1.0f,-1.0f, 1.0f,
128 -1.0f,-1.0f,-1.0f,
129 1.0f,-1.0f, 1.0f,
130 -1.0f,-1.0f, 1.0f,
131
132 -1.0f, 1.0f,-1.0f, // +Y side
133 -1.0f, 1.0f, 1.0f,
134 1.0f, 1.0f, 1.0f,
135 -1.0f, 1.0f,-1.0f,
136 1.0f, 1.0f, 1.0f,
137 1.0f, 1.0f,-1.0f,
138
139 1.0f, 1.0f,-1.0f, // +X side
140 1.0f, 1.0f, 1.0f,
141 1.0f,-1.0f, 1.0f,
142 1.0f,-1.0f, 1.0f,
143 1.0f,-1.0f,-1.0f,
144 1.0f, 1.0f,-1.0f,
145
146 -1.0f, 1.0f, 1.0f, // +Z side
147 -1.0f,-1.0f, 1.0f,
148 1.0f, 1.0f, 1.0f,
149 -1.0f,-1.0f, 1.0f,
150 1.0f,-1.0f, 1.0f,
151 1.0f, 1.0f, 1.0f,
152};
153
154static const float g_uv_buffer_data[] = {
155 0.0f, 1.0f, // -X side
156 1.0f, 1.0f,
157 1.0f, 0.0f,
158 1.0f, 0.0f,
159 0.0f, 0.0f,
160 0.0f, 1.0f,
161
162 1.0f, 1.0f, // -Z side
163 0.0f, 0.0f,
164 0.0f, 1.0f,
165 1.0f, 1.0f,
166 1.0f, 0.0f,
167 0.0f, 0.0f,
168
169 1.0f, 0.0f, // -Y side
170 1.0f, 1.0f,
171 0.0f, 1.0f,
172 1.0f, 0.0f,
173 0.0f, 1.0f,
174 0.0f, 0.0f,
175
176 1.0f, 0.0f, // +Y side
177 0.0f, 0.0f,
178 0.0f, 1.0f,
179 1.0f, 0.0f,
180 0.0f, 1.0f,
181 1.0f, 1.0f,
182
183 1.0f, 0.0f, // +X side
184 0.0f, 0.0f,
185 0.0f, 1.0f,
186 0.0f, 1.0f,
187 1.0f, 1.0f,
188 1.0f, 0.0f,
189
190 0.0f, 0.0f, // +Z side
191 0.0f, 1.0f,
192 1.0f, 0.0f,
193 0.0f, 1.0f,
194 1.0f, 1.0f,
195 1.0f, 0.0f,
196};
Jeremy Hayes9d304782016-10-09 11:48:12 -0600197// clang-format on
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600198
Jeremy Hayes9d304782016-10-09 11:48:12 -0600199typedef struct {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600200 vk::Image image;
201 vk::CommandBuffer cmd;
202 vk::CommandBuffer graphics_to_present_cmd;
203 vk::ImageView view;
204} SwapchainBuffers;
205
206#ifdef _WIN32
207// MS-Windows event handling function:
208LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
209#endif
210
Karl Schultz23cc2182016-11-23 17:15:17 -0700211#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700212static void handle_ping(void *data, wl_shell_surface *shell_surface, uint32_t serial) {
Karl Schultz23cc2182016-11-23 17:15:17 -0700213 wl_shell_surface_pong(shell_surface, serial);
214}
215
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700216static void handle_configure(void *data, wl_shell_surface *shell_surface, uint32_t edges, int32_t width, int32_t height) {}
Karl Schultz23cc2182016-11-23 17:15:17 -0700217
218static void handle_popup_done(void *data, wl_shell_surface *shell_surface) {}
219
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700220static const wl_shell_surface_listener shell_surface_listener = {handle_ping, handle_configure, handle_popup_done};
Karl Schultz23cc2182016-11-23 17:15:17 -0700221
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700222static void handle_announce_global_object(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface,
Karl Schultz23cc2182016-11-23 17:15:17 -0700223 uint32_t version) {}
224
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700225static void handle_announce_global_object_remove(void *data, struct wl_registry *wl_registry, uint32_t name) {}
Karl Schultz23cc2182016-11-23 17:15:17 -0700226
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700227static const wl_registry_listener registry_listener = {handle_announce_global_object, handle_announce_global_object_remove};
Tony Barbourefd0c5a2016-12-07 14:45:12 -0700228#elif defined(VK_USE_PLATFORM_MIR_KHR)
Karl Schultz23cc2182016-11-23 17:15:17 -0700229#endif
230
Jeremy Hayes9d304782016-10-09 11:48:12 -0600231struct Demo {
232 Demo()
233 :
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600234#if defined(VK_USE_PLATFORM_WIN32_KHR)
Jeremy Hayes9d304782016-10-09 11:48:12 -0600235 connection{nullptr},
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700236 window{nullptr}, minsize(POINT{0, 0}), // Use explicit construction to avoid MSVC error C2797.
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600237#endif
Tony Barbour153cb062016-12-07 13:43:36 -0700238
Tony Barbour78d6b572016-11-14 14:46:33 -0700239#if defined(VK_USE_PLATFORM_XLIB_KHR)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700240 xlib_window{0}, xlib_wm_delete_window{0}, display{nullptr},
Tony Barbour153cb062016-12-07 13:43:36 -0700241#elif defined(VK_USE_PLATFORM_XCB_KHR)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700242 xcb_window{0},
243 screen{nullptr}, connection{nullptr},
Karl Schultz23cc2182016-11-23 17:15:17 -0700244#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
245 display{nullptr},
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700246 registry{nullptr}, compositor{nullptr}, window{nullptr}, shell{nullptr}, shell_surface{nullptr},
Tony Barbourefd0c5a2016-12-07 14:45:12 -0700247#elif defined(VK_USE_PLATFORM_MIR_KHR)
Tony Barbour78d6b572016-11-14 14:46:33 -0700248#endif
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700249 prepared{false}, use_staging_buffer{false}, use_xlib{false}, graphics_queue_family_index{0},
250 present_queue_family_index{0}, enabled_extension_count{0}, enabled_layer_count{0}, width{0}, height{0},
251 swapchainImageCount{0}, frame_index{0}, spin_angle{0.0f}, spin_increment{0.0f}, pause{false}, quit{false}, curFrame{0},
252 frameCount{0}, validate{false}, use_break{false}, suppress_popups{false}, current_buffer{0}, queue_family_count{0} {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600253#if defined(VK_USE_PLATFORM_WIN32_KHR)
254 memset(name, '\0', APP_NAME_STR_LEN);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600255#endif
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600256 memset(projection_matrix, 0, sizeof(projection_matrix));
257 memset(view_matrix, 0, sizeof(view_matrix));
258 memset(model_matrix, 0, sizeof(model_matrix));
259 }
260
Jeremy Hayes9d304782016-10-09 11:48:12 -0600261 void build_image_ownership_cmd(uint32_t const &i) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700262 auto const cmd_buf_info = vk::CommandBufferBeginInfo().setFlags(vk::CommandBufferUsageFlagBits::eSimultaneousUse);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600263 auto result = buffers[i].graphics_to_present_cmd.begin(&cmd_buf_info);
264 VERIFY(result == vk::Result::eSuccess);
265
Jeremy Hayes9d304782016-10-09 11:48:12 -0600266 auto const image_ownership_barrier =
267 vk::ImageMemoryBarrier()
268 .setSrcAccessMask(vk::AccessFlags())
269 .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
270 .setOldLayout(vk::ImageLayout::ePresentSrcKHR)
271 .setNewLayout(vk::ImageLayout::ePresentSrcKHR)
272 .setSrcQueueFamilyIndex(graphics_queue_family_index)
273 .setDstQueueFamilyIndex(present_queue_family_index)
274 .setImage(buffers[i].image)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700275 .setSubresourceRange(vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600276
Jeremy Hayes9d304782016-10-09 11:48:12 -0600277 buffers[i].graphics_to_present_cmd.pipelineBarrier(
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700278 vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eColorAttachmentOutput,
279 vk::DependencyFlagBits(), 0, nullptr, 0, nullptr, 1, &image_ownership_barrier);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600280
281 result = buffers[i].graphics_to_present_cmd.end();
282 VERIFY(result == vk::Result::eSuccess);
283 }
284
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700285 vk::Bool32 check_layers(uint32_t check_count, char const *const *const check_names, uint32_t layer_count,
286 vk::LayerProperties *layers) {
Jeremy Hayes9d304782016-10-09 11:48:12 -0600287 for (uint32_t i = 0; i < check_count; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600288 vk::Bool32 found = VK_FALSE;
Jeremy Hayes9d304782016-10-09 11:48:12 -0600289 for (uint32_t j = 0; j < layer_count; j++) {
290 if (!strcmp(check_names[i], layers[j].layerName)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600291 found = VK_TRUE;
292 break;
293 }
294 }
Jeremy Hayes9d304782016-10-09 11:48:12 -0600295 if (!found) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600296 fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
297 return 0;
298 }
299 }
300 return VK_TRUE;
301 }
302
Jeremy Hayes9d304782016-10-09 11:48:12 -0600303 void cleanup() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600304 prepared = false;
305 device.waitIdle();
306
307 // Wait for fences from present operations
Jeremy Hayes9d304782016-10-09 11:48:12 -0600308 for (uint32_t i = 0; i < FRAME_LAG; i++) {
Jeremy Hayes43622622016-10-25 15:57:02 -0600309 device.waitForFences(1, &fences[i], VK_TRUE, UINT64_MAX);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600310 device.destroyFence(fences[i], nullptr);
311 device.destroySemaphore(image_acquired_semaphores[i], nullptr);
312 device.destroySemaphore(draw_complete_semaphores[i], nullptr);
Jeremy Hayes9d304782016-10-09 11:48:12 -0600313 if (separate_present_queue) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600314 device.destroySemaphore(image_ownership_semaphores[i], nullptr);
315 }
316 }
317
Jeremy Hayes9d304782016-10-09 11:48:12 -0600318 for (uint32_t i = 0; i < swapchainImageCount; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600319 device.destroyFramebuffer(framebuffers[i], nullptr);
320 }
321 device.destroyDescriptorPool(desc_pool, nullptr);
322
323 device.destroyPipeline(pipeline, nullptr);
324 device.destroyPipelineCache(pipelineCache, nullptr);
325 device.destroyRenderPass(render_pass, nullptr);
326 device.destroyPipelineLayout(pipeline_layout, nullptr);
327 device.destroyDescriptorSetLayout(desc_layout, nullptr);
328
Jeremy Hayes9d304782016-10-09 11:48:12 -0600329 for (uint32_t i = 0; i < texture_count; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600330 device.destroyImageView(textures[i].view, nullptr);
331 device.destroyImage(textures[i].image, nullptr);
332 device.freeMemory(textures[i].mem, nullptr);
333 device.destroySampler(textures[i].sampler, nullptr);
334 }
335 device.destroySwapchainKHR(swapchain, nullptr);
336
337 device.destroyImageView(depth.view, nullptr);
338 device.destroyImage(depth.image, nullptr);
339 device.freeMemory(depth.mem, nullptr);
340
341 device.destroyBuffer(uniform_data.buf, nullptr);
342 device.freeMemory(uniform_data.mem, nullptr);
343
Jeremy Hayes9d304782016-10-09 11:48:12 -0600344 for (uint32_t i = 0; i < swapchainImageCount; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600345 device.destroyImageView(buffers[i].view, nullptr);
346 device.freeCommandBuffers(cmd_pool, 1, &buffers[i].cmd);
347 }
348
349 device.destroyCommandPool(cmd_pool, nullptr);
350
Jeremy Hayes9d304782016-10-09 11:48:12 -0600351 if (separate_present_queue) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600352 device.destroyCommandPool(present_cmd_pool, nullptr);
353 }
Jeremy Hayes32633cb2016-11-16 14:54:41 -0700354 device.waitIdle();
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600355 device.destroy(nullptr);
356 inst.destroySurfaceKHR(surface, nullptr);
357 inst.destroy(nullptr);
358
Tony Barbour153cb062016-12-07 13:43:36 -0700359#if defined(VK_USE_PLATFORM_XLIB_KHR)
Tony Barbour78d6b572016-11-14 14:46:33 -0700360 XDestroyWindow(display, xlib_window);
361 XCloseDisplay(display);
362#elif defined(VK_USE_PLATFORM_XCB_KHR)
363 xcb_destroy_window(connection, xcb_window);
364 xcb_disconnect(connection);
365 free(atom_wm_delete_window);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600366#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
367 wl_shell_surface_destroy(shell_surface);
368 wl_surface_destroy(window);
369 wl_shell_destroy(shell);
370 wl_compositor_destroy(compositor);
371 wl_registry_destroy(registry);
372 wl_display_disconnect(display);
Tony Barbourefd0c5a2016-12-07 14:45:12 -0700373#elif defined(VK_USE_PLATFORM_MIR_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600374#endif
375 }
376
Jeremy Hayes9d304782016-10-09 11:48:12 -0600377 void create_device() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600378 float const priorities[1] = {0.0};
379
380 vk::DeviceQueueCreateInfo queues[2];
381 queues[0].setQueueFamilyIndex(graphics_queue_family_index);
382 queues[0].setQueueCount(1);
383 queues[0].setPQueuePriorities(priorities);
384
385 auto deviceInfo = vk::DeviceCreateInfo()
Jeremy Hayes9d304782016-10-09 11:48:12 -0600386 .setQueueCreateInfoCount(1)
387 .setPQueueCreateInfos(queues)
388 .setEnabledLayerCount(0)
389 .setPpEnabledLayerNames(nullptr)
390 .setEnabledExtensionCount(enabled_extension_count)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700391 .setPpEnabledExtensionNames((const char *const *)extension_names)
Jeremy Hayes9d304782016-10-09 11:48:12 -0600392 .setPEnabledFeatures(nullptr);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600393
Jeremy Hayes9d304782016-10-09 11:48:12 -0600394 if (separate_present_queue) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600395 queues[1].setQueueFamilyIndex(present_queue_family_index);
396 queues[1].setQueueCount(1);
397 queues[1].setPQueuePriorities(priorities);
398 deviceInfo.setQueueCreateInfoCount(2);
399 }
400
401 auto result = gpu.createDevice(&deviceInfo, nullptr, &device);
402 VERIFY(result == vk::Result::eSuccess);
403 }
404
Jeremy Hayes9d304782016-10-09 11:48:12 -0600405 void destroy_texture_image(texture_object *tex_objs) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600406 // clean up staging resources
407 device.freeMemory(tex_objs->mem, nullptr);
408 device.destroyImage(tex_objs->image, nullptr);
409 }
410
Jeremy Hayes9d304782016-10-09 11:48:12 -0600411 void draw() {
Jeremy Hayes43622622016-10-25 15:57:02 -0600412 // Ensure no more than FRAME_LAG presentations are outstanding
413 device.waitForFences(1, &fences[frame_index], VK_TRUE, UINT64_MAX);
414 device.resetFences(1, &fences[frame_index]);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600415
416 // Get the index of the next available swapchain image:
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700417 auto result = device.acquireNextImageKHR(swapchain, UINT64_MAX, image_acquired_semaphores[frame_index], fences[frame_index],
418 &current_buffer);
Jeremy Hayes9d304782016-10-09 11:48:12 -0600419 if (result == vk::Result::eErrorOutOfDateKHR) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600420 // swapchain is out of date (e.g. the window was resized) and
421 // must be recreated:
422 frame_index += 1;
423 frame_index %= FRAME_LAG;
424
425 resize();
426 draw();
427 return;
Jeremy Hayes9d304782016-10-09 11:48:12 -0600428 } else if (result == vk::Result::eSuboptimalKHR) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600429 // swapchain is not as optimal as it could be, but the platform's
430 // presentation engine will still present the image correctly.
Jeremy Hayes9d304782016-10-09 11:48:12 -0600431 } else {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600432 VERIFY(result == vk::Result::eSuccess);
433 }
434
435 // Wait for the image acquired semaphore to be signaled to ensure
436 // that the image won't be rendered to until the presentation
437 // engine has fully released ownership to the application, and it is
438 // okay to render to the image.
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700439 vk::PipelineStageFlags const pipe_stage_flags = vk::PipelineStageFlagBits::eColorAttachmentOutput;
440 auto const submit_info = vk::SubmitInfo()
441 .setPWaitDstStageMask(&pipe_stage_flags)
442 .setWaitSemaphoreCount(1)
443 .setPWaitSemaphores(&image_acquired_semaphores[frame_index])
444 .setCommandBufferCount(1)
445 .setPCommandBuffers(&buffers[current_buffer].cmd)
446 .setSignalSemaphoreCount(1)
447 .setPSignalSemaphores(&draw_complete_semaphores[frame_index]);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600448
449 result = graphics_queue.submit(1, &submit_info, vk::Fence());
450 VERIFY(result == vk::Result::eSuccess);
451
Jeremy Hayes9d304782016-10-09 11:48:12 -0600452 if (separate_present_queue) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600453 // If we are using separate queues, change image ownership to the
454 // present queue before presenting, waiting for the draw complete
Jeremy Hayes9d304782016-10-09 11:48:12 -0600455 // semaphore and signalling the ownership released semaphore when
456 // finished
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700457 auto const submit_info = vk::SubmitInfo()
458 .setPWaitDstStageMask(&pipe_stage_flags)
459 .setWaitSemaphoreCount(1)
460 .setPWaitSemaphores(&draw_complete_semaphores[frame_index])
461 .setCommandBufferCount(1)
462 .setPCommandBuffers(&buffers[current_buffer].graphics_to_present_cmd)
463 .setSignalSemaphoreCount(1)
464 .setPSignalSemaphores(&image_ownership_semaphores[frame_index]);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600465
Jeremy Hayes9d304782016-10-09 11:48:12 -0600466 result = present_queue.submit(1, &submit_info, vk::Fence());
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600467 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
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700472 auto const presentInfo = vk::PresentInfoKHR()
473 .setWaitSemaphoreCount(1)
474 .setPWaitSemaphores(separate_present_queue ? &image_ownership_semaphores[frame_index]
475 : &draw_complete_semaphores[frame_index])
476 .setSwapchainCount(1)
477 .setPSwapchains(&swapchain)
478 .setPImageIndices(&current_buffer);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600479
480 result = present_queue.presentKHR(&presentInfo);
481 frame_index += 1;
482 frame_index %= FRAME_LAG;
Jeremy Hayes9d304782016-10-09 11:48:12 -0600483 if (result == vk::Result::eErrorOutOfDateKHR) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600484 // swapchain is out of date (e.g. the window was resized) and
485 // must be recreated:
486 resize();
Jeremy Hayes9d304782016-10-09 11:48:12 -0600487 } else if (result == vk::Result::eSuboptimalKHR) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600488 // swapchain is not as optimal as it could be, but the platform's
489 // presentation engine will still present the image correctly.
Jeremy Hayes9d304782016-10-09 11:48:12 -0600490 } else {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600491 VERIFY(result == vk::Result::eSuccess);
492 }
493 }
494
Jeremy Hayes9d304782016-10-09 11:48:12 -0600495 void draw_build_cmd(vk::CommandBuffer commandBuffer) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700496 auto const commandInfo = vk::CommandBufferBeginInfo().setFlags(vk::CommandBufferUsageFlagBits::eSimultaneousUse);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600497
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700498 vk::ClearValue const clearValues[2] = {vk::ClearColorValue(std::array<float, 4>({{0.2f, 0.2f, 0.2f, 0.2f}})),
499 vk::ClearDepthStencilValue(1.0f, 0u)};
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600500
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700501 auto const passInfo = vk::RenderPassBeginInfo()
502 .setRenderPass(render_pass)
503 .setFramebuffer(framebuffers[current_buffer])
504 .setRenderArea(vk::Rect2D(vk::Offset2D(0, 0), vk::Extent2D((uint32_t)width, (uint32_t)height)))
505 .setClearValueCount(2)
506 .setPClearValues(clearValues);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600507
508 auto result = commandBuffer.begin(&commandInfo);
509 VERIFY(result == vk::Result::eSuccess);
510
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600511 commandBuffer.beginRenderPass(&passInfo, vk::SubpassContents::eInline);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600512 commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700513 commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline_layout, 0, 1, &desc_set, 0, nullptr);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600514
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700515 auto const viewport =
516 vk::Viewport().setWidth((float)width).setHeight((float)height).setMinDepth((float)0.0f).setMaxDepth((float)1.0f);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600517 commandBuffer.setViewport(0, 1, &viewport);
518
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700519 vk::Rect2D const scissor(vk::Offset2D(0, 0), vk::Extent2D(width, height));
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600520 commandBuffer.setScissor(0, 1, &scissor);
521 commandBuffer.draw(12 * 3, 1, 0, 0);
522 // Note that ending the renderpass changes the image's layout from
523 // COLOR_ATTACHMENT_OPTIMAL to PRESENT_SRC_KHR
524 commandBuffer.endRenderPass();
525
Jeremy Hayes9d304782016-10-09 11:48:12 -0600526 if (separate_present_queue) {
527 // We have to transfer ownership from the graphics queue family to
528 // the
529 // present queue family to be able to present. Note that we don't
530 // have
531 // to transfer from present queue family back to graphics queue
532 // family at
533 // the start of the next frame because we don't care about the
534 // image's
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600535 // contents at that point.
Jeremy Hayes9d304782016-10-09 11:48:12 -0600536 auto const image_ownership_barrier =
537 vk::ImageMemoryBarrier()
538 .setSrcAccessMask(vk::AccessFlags())
539 .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
540 .setOldLayout(vk::ImageLayout::ePresentSrcKHR)
541 .setNewLayout(vk::ImageLayout::ePresentSrcKHR)
542 .setSrcQueueFamilyIndex(graphics_queue_family_index)
543 .setDstQueueFamilyIndex(present_queue_family_index)
544 .setImage(buffers[current_buffer].image)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700545 .setSubresourceRange(vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600546
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700547 commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput,
548 vk::PipelineStageFlagBits::eBottomOfPipe, vk::DependencyFlagBits(), 0, nullptr, 0,
549 nullptr, 1, &image_ownership_barrier);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600550 }
551
552 result = commandBuffer.end();
553 VERIFY(result == vk::Result::eSuccess);
554 }
555
Jeremy Hayes9d304782016-10-09 11:48:12 -0600556 void flush_init_cmd() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600557 // TODO: hmm.
Jeremy Hayes9d304782016-10-09 11:48:12 -0600558 // This function could get called twice if the texture uses a staging
559 // buffer
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600560 // In that case the second call should be ignored
Jeremy Hayes9d304782016-10-09 11:48:12 -0600561 if (!cmd) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600562 return;
563 }
564
565 auto result = cmd.end();
566 VERIFY(result == vk::Result::eSuccess);
567
Jeremy Hayes27f072e2016-11-18 11:59:55 -0700568 auto const fenceInfo = vk::FenceCreateInfo();
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600569 vk::Fence fence;
570 device.createFence(&fenceInfo, nullptr, &fence);
571
Jeremy Hayes9d304782016-10-09 11:48:12 -0600572 vk::CommandBuffer const commandBuffers[] = {cmd};
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700573 auto const submitInfo = vk::SubmitInfo().setCommandBufferCount(1).setPCommandBuffers(commandBuffers);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600574
575 result = graphics_queue.submit(1, &submitInfo, fence);
576 VERIFY(result == vk::Result::eSuccess);
577
578 result = device.waitForFences(1, &fence, VK_TRUE, UINT64_MAX);
579 VERIFY(result == vk::Result::eSuccess);
580
581 device.freeCommandBuffers(cmd_pool, 1, commandBuffers);
582 device.destroyFence(fence, nullptr);
583
584 cmd = vk::CommandBuffer();
585 }
586
Jeremy Hayes9d304782016-10-09 11:48:12 -0600587 void init(int argc, char **argv) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600588 vec3 eye = {0.0f, 3.0f, 5.0f};
589 vec3 origin = {0, 0, 0};
590 vec3 up = {0.0f, 1.0f, 0.0};
591
Jeremy Hayes6ae1f8a2016-11-16 14:47:13 -0700592 presentMode = vk::PresentModeKHR::eFifo;
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600593 frameCount = UINT32_MAX;
594 use_xlib = false;
595
596 for (int i = 1; i < argc; i++) {
Jeremy Hayes9d304782016-10-09 11:48:12 -0600597 if (strcmp(argv[i], "--use_staging") == 0) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600598 use_staging_buffer = true;
599 continue;
600 }
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700601 if ((strcmp(argv[i], "--present_mode") == 0) && (i < argc - 1)) {
602 presentMode = (vk::PresentModeKHR)atoi(argv[i + 1]);
Jeremy Hayes6ae1f8a2016-11-16 14:47:13 -0700603 i++;
604 continue;
605 }
Jeremy Hayes9d304782016-10-09 11:48:12 -0600606 if (strcmp(argv[i], "--break") == 0) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600607 use_break = true;
608 continue;
609 }
Jeremy Hayes9d304782016-10-09 11:48:12 -0600610 if (strcmp(argv[i], "--validate") == 0) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600611 validate = true;
612 continue;
613 }
Jeremy Hayes9d304782016-10-09 11:48:12 -0600614 if (strcmp(argv[i], "--xlib") == 0) {
Tony Barbour153cb062016-12-07 13:43:36 -0700615 fprintf(stderr, "--xlib is deprecated and no longer does anything");
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600616 continue;
617 }
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700618 if (strcmp(argv[i], "--c") == 0 && frameCount == UINT32_MAX && i < argc - 1 &&
619 sscanf(argv[i + 1], "%d", &frameCount) == 1) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600620 i++;
621 continue;
622 }
Jeremy Hayes9d304782016-10-09 11:48:12 -0600623 if (strcmp(argv[i], "--suppress_popups") == 0) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600624 suppress_popups = true;
625 continue;
626 }
627
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700628 fprintf(stderr, "Usage:\n %s [--use_staging] [--validate] [--break] "
629 "[--c <framecount>] [--suppress_popups] [--present_mode <present mode enum>]\n"
630 "VK_PRESENT_MODE_IMMEDIATE_KHR = %d\n"
631 "VK_PRESENT_MODE_MAILBOX_KHR = %d\n"
632 "VK_PRESENT_MODE_FIFO_KHR = %d\n"
633 "VK_PRESENT_MODE_FIFO_RELAXED_KHR = %d\n",
634 APP_SHORT_NAME, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
635 VK_PRESENT_MODE_FIFO_RELAXED_KHR);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600636 fflush(stderr);
637 exit(1);
638 }
639
Jeremy Hayes9d304782016-10-09 11:48:12 -0600640 if (!use_xlib) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600641 init_connection();
642 }
643
644 init_vk();
645
646 width = 500;
647 height = 500;
648
649 spin_angle = 4.0f;
650 spin_increment = 0.2f;
651 pause = false;
652
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700653 mat4x4_perspective(projection_matrix, (float)degreesToRadians(45.0f), 1.0f, 0.1f, 100.0f);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600654 mat4x4_look_at(view_matrix, eye, origin, up);
655 mat4x4_identity(model_matrix);
656
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700657 projection_matrix[1][1] *= -1; // Flip projection matrix from GL to Vulkan orientation.
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600658 }
659
Jeremy Hayes9d304782016-10-09 11:48:12 -0600660 void init_connection() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600661#if defined(VK_USE_PLATFORM_XCB_KHR)
662 const xcb_setup_t *setup;
663 xcb_screen_iterator_t iter;
664 int scr;
665
666 connection = xcb_connect(nullptr, &scr);
Jeremy Hayes9d304782016-10-09 11:48:12 -0600667 if (xcb_connection_has_error(connection) > 0) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600668 printf("Cannot find a compatible Vulkan installable client driver "
669 "(ICD).\nExiting ...\n");
670 fflush(stdout);
671 exit(1);
672 }
673
674 setup = xcb_get_setup(connection);
675 iter = xcb_setup_roots_iterator(setup);
Jeremy Hayes9d304782016-10-09 11:48:12 -0600676 while (scr-- > 0)
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600677 xcb_screen_next(&iter);
678
679 screen = iter.data;
680#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
681 display = wl_display_connect(nullptr);
682
Jeremy Hayes9d304782016-10-09 11:48:12 -0600683 if (display == nullptr) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600684 printf("Cannot find a compatible Vulkan installable client driver "
685 "(ICD).\nExiting ...\n");
686 fflush(stdout);
687 exit(1);
688 }
689
690 registry = wl_display_get_registry(display);
691 wl_registry_add_listener(registry, &registry_listener, this);
692 wl_display_dispatch(display);
Tony Barbourefd0c5a2016-12-07 14:45:12 -0700693#elif defined(VK_USE_PLATFORM_MIR_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600694#endif
695 }
696
Jeremy Hayes9d304782016-10-09 11:48:12 -0600697 void init_vk() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600698 uint32_t instance_extension_count = 0;
699 uint32_t instance_layer_count = 0;
700 uint32_t validation_layer_count = 0;
Jeremy Hayes9d304782016-10-09 11:48:12 -0600701 char const *const *instance_validation_layers = nullptr;
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600702 enabled_extension_count = 0;
703 enabled_layer_count = 0;
704
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700705 char const *const instance_validation_layers_alt1[] = {"VK_LAYER_LUNARG_standard_validation"};
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600706
Jeremy Hayes9d304782016-10-09 11:48:12 -0600707 char const *const instance_validation_layers_alt2[] = {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700708 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker",
709 "VK_LAYER_LUNARG_image", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain",
Jeremy Hayes9d304782016-10-09 11:48:12 -0600710 "VK_LAYER_GOOGLE_unique_objects"};
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600711
712 // Look for validation layers
713 vk::Bool32 validation_found = VK_FALSE;
Jeremy Hayes9d304782016-10-09 11:48:12 -0600714 if (validate) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700715 auto result = vk::enumerateInstanceLayerProperties(&instance_layer_count, nullptr);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600716 VERIFY(result == vk::Result::eSuccess);
717
718 instance_validation_layers = instance_validation_layers_alt1;
Jeremy Hayes9d304782016-10-09 11:48:12 -0600719 if (instance_layer_count > 0) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700720 std::unique_ptr<vk::LayerProperties[]> instance_layers(new vk::LayerProperties[instance_layer_count]);
721 result = vk::enumerateInstanceLayerProperties(&instance_layer_count, instance_layers.get());
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600722 VERIFY(result == vk::Result::eSuccess);
723
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700724 validation_found = check_layers(ARRAY_SIZE(instance_validation_layers_alt1), instance_validation_layers,
725 instance_layer_count, instance_layers.get());
Jeremy Hayes9d304782016-10-09 11:48:12 -0600726 if (validation_found) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700727 enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600728 enabled_layers[0] = "VK_LAYER_LUNARG_standard_validation";
729 validation_layer_count = 1;
Jeremy Hayes9d304782016-10-09 11:48:12 -0600730 } else {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600731 // use alternative set of validation layers
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700732 instance_validation_layers = instance_validation_layers_alt2;
733 enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
734 validation_found = check_layers(ARRAY_SIZE(instance_validation_layers_alt2), instance_validation_layers,
735 instance_layer_count, instance_layers.get());
736 validation_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
Jeremy Hayes9d304782016-10-09 11:48:12 -0600737 for (uint32_t i = 0; i < validation_layer_count; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600738 enabled_layers[i] = instance_validation_layers[i];
739 }
740 }
741 }
742
Jeremy Hayes9d304782016-10-09 11:48:12 -0600743 if (!validation_found) {
744 ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find "
745 "required validation layer.\n\n"
746 "Please look at the Getting Started guide for "
747 "additional information.\n",
748 "vkCreateInstance Failure");
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600749 }
750 }
751
752 /* Look for instance extensions */
753 vk::Bool32 surfaceExtFound = VK_FALSE;
754 vk::Bool32 platformSurfaceExtFound = VK_FALSE;
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600755 memset(extension_names, 0, sizeof(extension_names));
756
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700757 auto result = vk::enumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600758 VERIFY(result == vk::Result::eSuccess);
759
Jeremy Hayes9d304782016-10-09 11:48:12 -0600760 if (instance_extension_count > 0) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700761 std::unique_ptr<vk::ExtensionProperties[]> instance_extensions(new vk::ExtensionProperties[instance_extension_count]);
762 result = vk::enumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions.get());
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600763 VERIFY(result == vk::Result::eSuccess);
764
Jeremy Hayes9d304782016-10-09 11:48:12 -0600765 for (uint32_t i = 0; i < instance_extension_count; i++) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700766 if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600767 surfaceExtFound = 1;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700768 extension_names[enabled_extension_count++] = VK_KHR_SURFACE_EXTENSION_NAME;
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600769 }
770#if defined(VK_USE_PLATFORM_WIN32_KHR)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700771 if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600772 platformSurfaceExtFound = 1;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700773 extension_names[enabled_extension_count++] = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600774 }
Tony Barbour153cb062016-12-07 13:43:36 -0700775#elif defined(VK_USE_PLATFORM_XLIB_KHR)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700776 if (!strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600777 platformSurfaceExtFound = 1;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700778 extension_names[enabled_extension_count++] = VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600779 }
Tony Barbour153cb062016-12-07 13:43:36 -0700780#elif defined(VK_USE_PLATFORM_XCB_KHR)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700781 if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600782 platformSurfaceExtFound = 1;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700783 extension_names[enabled_extension_count++] = VK_KHR_XCB_SURFACE_EXTENSION_NAME;
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600784 }
Tony Barbour153cb062016-12-07 13:43:36 -0700785#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700786 if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600787 platformSurfaceExtFound = 1;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700788 extension_names[enabled_extension_count++] = VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600789 }
Tony Barbourefd0c5a2016-12-07 14:45:12 -0700790#elif defined(VK_USE_PLATFORM_MIR_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600791#endif
792 assert(enabled_extension_count < 64);
793 }
794 }
795
Jeremy Hayes9d304782016-10-09 11:48:12 -0600796 if (!surfaceExtFound) {
797 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
798 "the " VK_KHR_SURFACE_EXTENSION_NAME " extension.\n\n"
799 "Do you have a compatible Vulkan installable client "
800 "driver (ICD) installed?\n"
801 "Please look at the Getting Started guide for additional "
802 "information.\n",
803 "vkCreateInstance Failure");
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600804 }
805
Jeremy Hayes9d304782016-10-09 11:48:12 -0600806 if (!platformSurfaceExtFound) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600807#if defined(VK_USE_PLATFORM_WIN32_KHR)
Jeremy Hayes9d304782016-10-09 11:48:12 -0600808 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700809 "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME " extension.\n\n"
Jeremy Hayes9d304782016-10-09 11:48:12 -0600810 "Do you have a compatible Vulkan installable client "
811 "driver (ICD) installed?\n"
812 "Please look at the Getting Started guide for additional "
813 "information.\n",
814 "vkCreateInstance Failure");
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600815#elif defined(VK_USE_PLATFORM_XCB_KHR)
Jeremy Hayes9d304782016-10-09 11:48:12 -0600816 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
817 "the " VK_KHR_XCB_SURFACE_EXTENSION_NAME " extension.\n\n"
818 "Do you have a compatible Vulkan installable client "
819 "driver (ICD) installed?\n"
820 "Please look at the Getting Started guide for additional "
821 "information.\n",
822 "vkCreateInstance Failure");
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600823#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
Jeremy Hayes9d304782016-10-09 11:48:12 -0600824 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700825 "the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME " extension.\n\n"
Jeremy Hayes9d304782016-10-09 11:48:12 -0600826 "Do you have a compatible Vulkan installable client "
827 "driver (ICD) installed?\n"
828 "Please look at the Getting Started guide for additional "
829 "information.\n",
830 "vkCreateInstance Failure");
Tony Barbourefd0c5a2016-12-07 14:45:12 -0700831#elif defined(VK_USE_PLATFORM_MIR_KHR)
Tony Barbour153cb062016-12-07 13:43:36 -0700832#elif defined(VK_USE_PLATFORM_XLIB_KHR)
Jeremy Hayes9d304782016-10-09 11:48:12 -0600833 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
834 "the " VK_KHR_XLIB_SURFACE_EXTENSION_NAME " extension.\n\n"
835 "Do you have a compatible Vulkan installable client "
836 "driver (ICD) installed?\n"
837 "Please look at the Getting Started guide for additional "
838 "information.\n",
839 "vkCreateInstance Failure");
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600840#endif
Tony Barbour153cb062016-12-07 13:43:36 -0700841 }
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600842 auto const app = vk::ApplicationInfo()
Jeremy Hayes9d304782016-10-09 11:48:12 -0600843 .setPApplicationName(APP_SHORT_NAME)
844 .setApplicationVersion(0)
845 .setPEngineName(APP_SHORT_NAME)
846 .setEngineVersion(0)
847 .setApiVersion(VK_API_VERSION_1_0);
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700848 auto const inst_info = vk::InstanceCreateInfo()
849 .setPApplicationInfo(&app)
850 .setEnabledLayerCount(enabled_layer_count)
851 .setPpEnabledLayerNames(instance_validation_layers)
852 .setEnabledExtensionCount(enabled_extension_count)
853 .setPpEnabledExtensionNames(extension_names);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600854
855 result = vk::createInstance(&inst_info, nullptr, &inst);
Jeremy Hayes9d304782016-10-09 11:48:12 -0600856 if (result == vk::Result::eErrorIncompatibleDriver) {
857 ERR_EXIT("Cannot find a compatible Vulkan installable client "
858 "driver (ICD).\n\n"
859 "Please look at the Getting Started guide for additional "
860 "information.\n",
861 "vkCreateInstance Failure");
862 } else if (result == vk::Result::eErrorExtensionNotPresent) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600863 ERR_EXIT("Cannot find a specified extension library.\n"
Jeremy Hayes9d304782016-10-09 11:48:12 -0600864 "Make sure your layers path is set appropriately.\n",
865 "vkCreateInstance Failure");
866 } else if (result != vk::Result::eSuccess) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600867 ERR_EXIT("vkCreateInstance failed.\n\n"
Jeremy Hayes9d304782016-10-09 11:48:12 -0600868 "Do you have a compatible Vulkan installable client "
869 "driver (ICD) installed?\n"
870 "Please look at the Getting Started guide for additional "
871 "information.\n",
872 "vkCreateInstance Failure");
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600873 }
874
875 /* Make initial call to query gpu_count, then second call for gpu info*/
876 uint32_t gpu_count;
877 result = inst.enumeratePhysicalDevices(&gpu_count, nullptr);
878 VERIFY(result == vk::Result::eSuccess);
879 assert(gpu_count > 0);
880
Jeremy Hayes9d304782016-10-09 11:48:12 -0600881 if (gpu_count > 0) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700882 std::unique_ptr<vk::PhysicalDevice[]> physical_devices(new vk::PhysicalDevice[gpu_count]);
883 result = inst.enumeratePhysicalDevices(&gpu_count, physical_devices.get());
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600884 VERIFY(result == vk::Result::eSuccess);
885 /* For cube demo we just grab the first physical device */
886 gpu = physical_devices[0];
Jeremy Hayes9d304782016-10-09 11:48:12 -0600887 } else {
888 ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible "
889 "devices.\n\n"
890 "Do you have a compatible Vulkan installable client "
891 "driver (ICD) installed?\n"
892 "Please look at the Getting Started guide for additional "
893 "information.\n",
894 "vkEnumeratePhysicalDevices Failure");
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600895 }
896
897 /* Look for device extensions */
898 uint32_t device_extension_count = 0;
899 vk::Bool32 swapchainExtFound = VK_FALSE;
900 enabled_extension_count = 0;
901 memset(extension_names, 0, sizeof(extension_names));
902
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700903 result = gpu.enumerateDeviceExtensionProperties(nullptr, &device_extension_count, nullptr);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600904 VERIFY(result == vk::Result::eSuccess);
905
Jeremy Hayes9d304782016-10-09 11:48:12 -0600906 if (device_extension_count > 0) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700907 std::unique_ptr<vk::ExtensionProperties[]> device_extensions(new vk::ExtensionProperties[device_extension_count]);
908 result = gpu.enumerateDeviceExtensionProperties(nullptr, &device_extension_count, device_extensions.get());
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600909 VERIFY(result == vk::Result::eSuccess);
910
Jeremy Hayes9d304782016-10-09 11:48:12 -0600911 for (uint32_t i = 0; i < device_extension_count; i++) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700912 if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, device_extensions[i].extensionName)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600913 swapchainExtFound = 1;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700914 extension_names[enabled_extension_count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600915 }
916 assert(enabled_extension_count < 64);
917 }
918 }
919
Jeremy Hayes9d304782016-10-09 11:48:12 -0600920 if (!swapchainExtFound) {
921 ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find "
922 "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME " extension.\n\n"
923 "Do you have a compatible Vulkan installable client "
924 "driver (ICD) installed?\n"
925 "Please look at the Getting Started guide for additional "
926 "information.\n",
927 "vkCreateInstance Failure");
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600928 }
929
930 gpu.getProperties(&gpu_props);
931
932 /* Call with nullptr data to get count */
933 gpu.getQueueFamilyProperties(&queue_family_count, nullptr);
934 assert(queue_family_count >= 1);
935
936 queue_props.reset(new vk::QueueFamilyProperties[queue_family_count]);
937 gpu.getQueueFamilyProperties(&queue_family_count, queue_props.get());
938
939 // Query fine-grained feature support for this device.
940 // If app has specific feature requirements it should check supported
941 // features based on this query
942 vk::PhysicalDeviceFeatures physDevFeatures;
943 gpu.getFeatures(&physDevFeatures);
944 }
945
Jeremy Hayes9d304782016-10-09 11:48:12 -0600946 void init_vk_swapchain() {
947// Create a WSI surface for the window:
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600948#if defined(VK_USE_PLATFORM_WIN32_KHR)
949 {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700950 auto const createInfo = vk::Win32SurfaceCreateInfoKHR().setHinstance(connection).setHwnd(window);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600951
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700952 auto result = inst.createWin32SurfaceKHR(&createInfo, nullptr, &surface);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600953 VERIFY(result == vk::Result::eSuccess);
954 }
Tony Barbour153cb062016-12-07 13:43:36 -0700955#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600956 {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700957 auto const createInfo = vk::WaylandSurfaceCreateInfoKHR().setDisplay(display).setSurface(window);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600958
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700959 auto result = inst.createWaylandSurfaceKHR(&createInfo, nullptr, &surface);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600960 VERIFY(result == vk::Result::eSuccess);
961 }
Tony Barbourefd0c5a2016-12-07 14:45:12 -0700962#elif defined(VK_USE_PLATFORM_MIR_KHR)
Tony Barbour153cb062016-12-07 13:43:36 -0700963#elif defined(VK_USE_PLATFORM_XLIB_KHR)
964 {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700965 auto const createInfo = vk::XlibSurfaceCreateInfoKHR().setDpy(display).setWindow(xlib_window);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600966
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700967 auto result = inst.createXlibSurfaceKHR(&createInfo, nullptr, &surface);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600968 VERIFY(result == vk::Result::eSuccess);
Tony Barbour153cb062016-12-07 13:43:36 -0700969 }
970#elif defined(VK_USE_PLATFORM_XCB_KHR)
971 {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700972 auto const createInfo = vk::XcbSurfaceCreateInfoKHR().setConnection(connection).setWindow(xcb_window);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600973
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700974 auto result = inst.createXcbSurfaceKHR(&createInfo, nullptr, &surface);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600975 VERIFY(result == vk::Result::eSuccess);
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600976 }
Tony Barbour153cb062016-12-07 13:43:36 -0700977#endif
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600978 // Iterate over each queue to learn whether it supports presenting:
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -0700979 std::unique_ptr<vk::Bool32[]> supportsPresent(new vk::Bool32[queue_family_count]);
Jeremy Hayes9d304782016-10-09 11:48:12 -0600980 for (uint32_t i = 0; i < queue_family_count; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600981 gpu.getSurfaceSupportKHR(i, surface, &supportsPresent[i]);
982 }
983
984 uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
985 uint32_t presentQueueFamilyIndex = UINT32_MAX;
Jeremy Hayes9d304782016-10-09 11:48:12 -0600986 for (uint32_t i = 0; i < queue_family_count; i++) {
987 if (queue_props[i].queueFlags & vk::QueueFlagBits::eGraphics) {
988 if (graphicsQueueFamilyIndex == UINT32_MAX) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600989 graphicsQueueFamilyIndex = i;
990 }
991
Jeremy Hayes9d304782016-10-09 11:48:12 -0600992 if (supportsPresent[i] == VK_TRUE) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -0600993 graphicsQueueFamilyIndex = i;
994 presentQueueFamilyIndex = i;
995 break;
996 }
997 }
998 }
999
Jeremy Hayes9d304782016-10-09 11:48:12 -06001000 if (presentQueueFamilyIndex == UINT32_MAX) {
1001 // If didn't find a queue that supports both graphics and present,
1002 // then
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001003 // find a separate present queue.
Jeremy Hayes9d304782016-10-09 11:48:12 -06001004 for (uint32_t i = 0; i < queue_family_count; ++i) {
1005 if (supportsPresent[i] == VK_TRUE) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001006 presentQueueFamilyIndex = i;
1007 break;
1008 }
1009 }
1010 }
1011
1012 // Generate error if could not find both a graphics and a present queue
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001013 if (graphicsQueueFamilyIndex == UINT32_MAX || presentQueueFamilyIndex == UINT32_MAX) {
1014 ERR_EXIT("Could not find both graphics and present queues\n", "Swapchain Initialization Failure");
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001015 }
1016
1017 graphics_queue_family_index = graphicsQueueFamilyIndex;
1018 present_queue_family_index = presentQueueFamilyIndex;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001019 separate_present_queue = (graphics_queue_family_index != present_queue_family_index);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001020
1021 create_device();
1022
1023 device.getQueue(graphics_queue_family_index, 0, &graphics_queue);
Jeremy Hayes9d304782016-10-09 11:48:12 -06001024 if (!separate_present_queue) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001025 present_queue = graphics_queue;
Jeremy Hayes9d304782016-10-09 11:48:12 -06001026 } else {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001027 device.getQueue(present_queue_family_index, 0, &present_queue);
1028 }
1029
1030 // Get the list of VkFormat's that are supported:
1031 uint32_t formatCount;
1032 auto result = gpu.getSurfaceFormatsKHR(surface, &formatCount, nullptr);
1033 VERIFY(result == vk::Result::eSuccess);
1034
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001035 std::unique_ptr<vk::SurfaceFormatKHR[]> surfFormats(new vk::SurfaceFormatKHR[formatCount]);
1036 result = gpu.getSurfaceFormatsKHR(surface, &formatCount, surfFormats.get());
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001037 VERIFY(result == vk::Result::eSuccess);
1038
1039 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
1040 // the surface has no preferred format. Otherwise, at least one
1041 // supported format will be returned.
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001042 if (formatCount == 1 && surfFormats[0].format == vk::Format::eUndefined) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001043 format = vk::Format::eB8G8R8A8Unorm;
Jeremy Hayes9d304782016-10-09 11:48:12 -06001044 } else {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001045 assert(formatCount >= 1);
1046 format = surfFormats[0].format;
1047 }
1048 color_space = surfFormats[0].colorSpace;
1049
1050 quit = false;
1051 curFrame = 0;
1052
1053 // Create semaphores to synchronize acquiring presentable buffers before
1054 // rendering and waiting for drawing to be complete before presenting
1055 auto const semaphoreCreateInfo = vk::SemaphoreCreateInfo();
1056
1057 // Create fences that we can use to throttle if we get too far
1058 // ahead of the image presents
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001059 auto const fence_ci = vk::FenceCreateInfo().setFlags(vk::FenceCreateFlagBits::eSignaled);
Jeremy Hayes9d304782016-10-09 11:48:12 -06001060 for (uint32_t i = 0; i < FRAME_LAG; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001061 device.createFence(&fence_ci, nullptr, &fences[i]);
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001062 result = device.createSemaphore(&semaphoreCreateInfo, nullptr, &image_acquired_semaphores[i]);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001063 VERIFY(result == vk::Result::eSuccess);
1064
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001065 result = device.createSemaphore(&semaphoreCreateInfo, nullptr, &draw_complete_semaphores[i]);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001066 VERIFY(result == vk::Result::eSuccess);
1067
Jeremy Hayes9d304782016-10-09 11:48:12 -06001068 if (separate_present_queue) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001069 result = device.createSemaphore(&semaphoreCreateInfo, nullptr, &image_ownership_semaphores[i]);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001070 VERIFY(result == vk::Result::eSuccess);
1071 }
1072 }
1073 frame_index = 0;
1074
1075 // Get Memory information and properties
1076 gpu.getMemoryProperties(&memory_properties);
1077 }
1078
Jeremy Hayes9d304782016-10-09 11:48:12 -06001079 void prepare() {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001080 auto const cmd_pool_info = vk::CommandPoolCreateInfo().setQueueFamilyIndex(graphics_queue_family_index);
1081 auto result = device.createCommandPool(&cmd_pool_info, nullptr, &cmd_pool);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001082 VERIFY(result == vk::Result::eSuccess);
1083
1084 auto const cmd = vk::CommandBufferAllocateInfo()
Jeremy Hayes9d304782016-10-09 11:48:12 -06001085 .setCommandPool(cmd_pool)
1086 .setLevel(vk::CommandBufferLevel::ePrimary)
1087 .setCommandBufferCount(1);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001088
Jeremy Hayes233130a2016-11-16 13:42:08 -07001089 result = device.allocateCommandBuffers(&cmd, &this->cmd);
1090 VERIFY(result == vk::Result::eSuccess);
1091
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001092 auto const cmd_buf_info = vk::CommandBufferBeginInfo().setPInheritanceInfo(nullptr);
Jeremy Hayes233130a2016-11-16 13:42:08 -07001093
1094 result = this->cmd.begin(&cmd_buf_info);
1095 VERIFY(result == vk::Result::eSuccess);
1096
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001097 prepare_buffers();
1098 prepare_depth();
1099 prepare_textures();
1100 prepare_cube_data_buffer();
1101
1102 prepare_descriptor_layout();
1103 prepare_render_pass();
1104 prepare_pipeline();
1105
Jeremy Hayes9d304782016-10-09 11:48:12 -06001106 for (uint32_t i = 0; i < swapchainImageCount; ++i) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001107 result = device.allocateCommandBuffers(&cmd, &buffers[i].cmd);
1108 VERIFY(result == vk::Result::eSuccess);
1109 }
1110
Jeremy Hayes9d304782016-10-09 11:48:12 -06001111 if (separate_present_queue) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001112 auto const cmd_pool_info = vk::CommandPoolCreateInfo().setQueueFamilyIndex(present_queue_family_index);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001113
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001114 result = device.createCommandPool(&cmd_pool_info, nullptr, &present_cmd_pool);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001115 VERIFY(result == vk::Result::eSuccess);
1116
1117 auto const cmd = vk::CommandBufferAllocateInfo()
Jeremy Hayes9d304782016-10-09 11:48:12 -06001118 .setCommandPool(present_cmd_pool)
1119 .setLevel(vk::CommandBufferLevel::ePrimary)
1120 .setCommandBufferCount(1);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001121
Jeremy Hayes9d304782016-10-09 11:48:12 -06001122 for (uint32_t i = 0; i < swapchainImageCount; i++) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001123 result = device.allocateCommandBuffers(&cmd, &buffers[i].graphics_to_present_cmd);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001124 VERIFY(result == vk::Result::eSuccess);
1125
1126 build_image_ownership_cmd(i);
1127 }
1128 }
1129
1130 prepare_descriptor_pool();
1131 prepare_descriptor_set();
1132
1133 prepare_framebuffers();
1134
Jeremy Hayes9d304782016-10-09 11:48:12 -06001135 for (uint32_t i = 0; i < swapchainImageCount; ++i) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001136 current_buffer = i;
1137 draw_build_cmd(buffers[i].cmd);
1138 }
1139
1140 /*
1141 * Prepare functions above may generate pipeline commands
1142 * that need to be flushed before beginning the render loop.
1143 */
1144 flush_init_cmd();
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001145 if (staging_texture.image) {
Jeremy Hayes1db0cee2016-11-16 14:15:25 -07001146 destroy_texture_image(&staging_texture);
1147 }
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001148
1149 current_buffer = 0;
1150 prepared = true;
1151 }
1152
Jeremy Hayes9d304782016-10-09 11:48:12 -06001153 void prepare_buffers() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001154 vk::SwapchainKHR oldSwapchain = swapchain;
1155
1156 // Check the surface capabilities and formats
1157 vk::SurfaceCapabilitiesKHR surfCapabilities;
1158 auto result = gpu.getSurfaceCapabilitiesKHR(surface, &surfCapabilities);
1159 VERIFY(result == vk::Result::eSuccess);
1160
1161 uint32_t presentModeCount;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001162 result = gpu.getSurfacePresentModesKHR(surface, &presentModeCount, nullptr);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001163 VERIFY(result == vk::Result::eSuccess);
1164
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001165 std::unique_ptr<vk::PresentModeKHR[]> presentModes(new vk::PresentModeKHR[presentModeCount]);
1166 result = gpu.getSurfacePresentModesKHR(surface, &presentModeCount, presentModes.get());
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001167 VERIFY(result == vk::Result::eSuccess);
1168
1169 vk::Extent2D swapchainExtent;
1170 // width and height are either both -1, or both not -1.
Jeremy Hayes9d304782016-10-09 11:48:12 -06001171 if (surfCapabilities.currentExtent.width == (uint32_t)-1) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001172 // If the surface size is undefined, the size is set to
1173 // the size of the images requested.
1174 swapchainExtent.width = width;
1175 swapchainExtent.height = height;
Jeremy Hayes9d304782016-10-09 11:48:12 -06001176 } else {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001177 // If the surface size is defined, the swap chain size must match
1178 swapchainExtent = surfCapabilities.currentExtent;
1179 width = surfCapabilities.currentExtent.width;
1180 height = surfCapabilities.currentExtent.height;
1181 }
1182
1183 // The FIFO present mode is guaranteed by the spec to be supported
1184 // and to have no tearing. It's a great default present mode to use.
1185 vk::PresentModeKHR swapchainPresentMode = vk::PresentModeKHR::eFifo;
1186
Jeremy Hayes6ae1f8a2016-11-16 14:47:13 -07001187 // There are times when you may wish to use another present mode. The
1188 // following code shows how to select them, and the comments provide some
1189 // reasons you may wish to use them.
1190 //
1191 // It should be noted that Vulkan 1.0 doesn't provide a method for
1192 // synchronizing rendering with the presentation engine's display. There
1193 // is a method provided for throttling rendering with the display, but
1194 // there are some presentation engines for which this method will not work.
1195 // If an application doesn't throttle its rendering, and if it renders much
1196 // faster than the refresh rate of the display, this can waste power on
1197 // mobile devices. That is because power is being spent rendering images
1198 // that may never be seen.
1199
Jeremy Hayes9d304782016-10-09 11:48:12 -06001200 // VK_PRESENT_MODE_IMMEDIATE_KHR is for applications that don't care
1201 // about
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001202 // tearing, or have some way of synchronizing their rendering with the
1203 // display.
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001204 // VK_PRESENT_MODE_MAILBOX_KHR may be useful for applications that
1205 // generally render a new presentable image every refresh cycle, but are
Jeremy Hayes9d304782016-10-09 11:48:12 -06001206 // occasionally early. In this case, the application wants the new
1207 // image
1208 // to be displayed instead of the previously-queued-for-presentation
1209 // image
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001210 // that has not yet been displayed.
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001211 // VK_PRESENT_MODE_FIFO_RELAXED_KHR is for applications that generally
Jeremy Hayes9d304782016-10-09 11:48:12 -06001212 // render a new presentable image every refresh cycle, but are
1213 // occasionally
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001214 // late. In this case (perhaps because of stuttering/latency concerns),
Jeremy Hayes9d304782016-10-09 11:48:12 -06001215 // the application wants the late image to be immediately displayed,
1216 // even
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001217 // though that may mean some tearing.
Jeremy Hayes6ae1f8a2016-11-16 14:47:13 -07001218
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001219 if (presentMode != swapchainPresentMode) {
Jeremy Hayes6ae1f8a2016-11-16 14:47:13 -07001220 for (size_t i = 0; i < presentModeCount; ++i) {
1221 if (presentModes[i] == presentMode) {
1222 swapchainPresentMode = presentMode;
1223 break;
1224 }
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001225 }
1226 }
Jeremy Hayes6ae1f8a2016-11-16 14:47:13 -07001227
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001228 if (swapchainPresentMode != presentMode) {
Jeremy Hayes6ae1f8a2016-11-16 14:47:13 -07001229 ERR_EXIT("Present mode specified is not supported\n", "Present mode unsupported");
1230 }
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001231
Jeremy Hayes9d304782016-10-09 11:48:12 -06001232 // Determine the number of VkImage's to use in the swap chain (we desire
1233 // to
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001234 // own only 1 image at a time, besides the images being displayed and
1235 // queued for display):
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001236 uint32_t desiredNumberOfSwapchainImages = surfCapabilities.minImageCount + 1;
Jeremy Hayes9d304782016-10-09 11:48:12 -06001237 // If maxImageCount is 0, we can ask for as many images as we want,
1238 // otherwise
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001239 // we're limited to maxImageCount
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001240 if ((surfCapabilities.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCapabilities.maxImageCount)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001241 // Application must settle for fewer images than desired:
1242 desiredNumberOfSwapchainImages = surfCapabilities.maxImageCount;
1243 }
1244
1245 vk::SurfaceTransformFlagBitsKHR preTransform;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001246 if (surfCapabilities.supportedTransforms & vk::SurfaceTransformFlagBitsKHR::eIdentity) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001247 preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
Jeremy Hayes9d304782016-10-09 11:48:12 -06001248 } else {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001249 preTransform = surfCapabilities.currentTransform;
1250 }
1251
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001252 auto const swapchain_ci = vk::SwapchainCreateInfoKHR()
1253 .setSurface(surface)
1254 .setMinImageCount(desiredNumberOfSwapchainImages)
1255 .setImageFormat(format)
1256 .setImageColorSpace(color_space)
1257 .setImageExtent({swapchainExtent.width, swapchainExtent.height})
1258 .setImageArrayLayers(1)
1259 .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment)
1260 .setImageSharingMode(vk::SharingMode::eExclusive)
1261 .setQueueFamilyIndexCount(0)
1262 .setPQueueFamilyIndices(nullptr)
1263 .setPreTransform(preTransform)
1264 .setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque)
1265 .setPresentMode(swapchainPresentMode)
1266 .setClipped(true)
1267 .setOldSwapchain(oldSwapchain);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001268
1269 result = device.createSwapchainKHR(&swapchain_ci, nullptr, &swapchain);
1270 VERIFY(result == vk::Result::eSuccess);
1271
Jeremy Hayes9d304782016-10-09 11:48:12 -06001272 // If we just re-created an existing swapchain, we should destroy the
1273 // old
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001274 // swapchain at this point.
1275 // Note: destroying the swapchain also cleans up all its associated
1276 // presentable images once the platform is done with them.
Jeremy Hayes9d304782016-10-09 11:48:12 -06001277 if (oldSwapchain) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001278 device.destroySwapchainKHR(oldSwapchain, nullptr);
1279 }
1280
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001281 result = device.getSwapchainImagesKHR(swapchain, &swapchainImageCount, nullptr);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001282 VERIFY(result == vk::Result::eSuccess);
1283
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001284 std::unique_ptr<vk::Image[]> swapchainImages(new vk::Image[swapchainImageCount]);
1285 result = device.getSwapchainImagesKHR(swapchain, &swapchainImageCount, swapchainImages.get());
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001286 VERIFY(result == vk::Result::eSuccess);
1287
1288 buffers.reset(new SwapchainBuffers[swapchainImageCount]);
1289
Jeremy Hayes9d304782016-10-09 11:48:12 -06001290 for (uint32_t i = 0; i < swapchainImageCount; ++i) {
1291 auto const color_image_view =
1292 vk::ImageViewCreateInfo()
1293 .setImage(swapchainImages[i])
1294 .setViewType(vk::ImageViewType::e2D)
1295 .setFormat(format)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001296 .setSubresourceRange(vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001297
1298 buffers[i].image = swapchainImages[i];
1299
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001300 result = device.createImageView(&color_image_view, nullptr, &buffers[i].view);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001301 VERIFY(result == vk::Result::eSuccess);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001302 }
1303 }
1304
Jeremy Hayes9d304782016-10-09 11:48:12 -06001305 void prepare_cube_data_buffer() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001306 mat4x4 VP;
1307 mat4x4_mul(VP, projection_matrix, view_matrix);
1308
1309 mat4x4 MVP;
1310 mat4x4_mul(MVP, VP, model_matrix);
1311
1312 vktexcube_vs_uniform data;
1313 memcpy(data.mvp, MVP, sizeof(MVP));
1314 // dumpMatrix("MVP", MVP)
Jeremy Hayes9d304782016-10-09 11:48:12 -06001315 for (int32_t i = 0; i < 12 * 3; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001316 data.position[i][0] = g_vertex_buffer_data[i * 3];
1317 data.position[i][1] = g_vertex_buffer_data[i * 3 + 1];
1318 data.position[i][2] = g_vertex_buffer_data[i * 3 + 2];
1319 data.position[i][3] = 1.0f;
1320 data.attr[i][0] = g_uv_buffer_data[2 * i];
1321 data.attr[i][1] = g_uv_buffer_data[2 * i + 1];
1322 data.attr[i][2] = 0;
1323 data.attr[i][3] = 0;
1324 }
1325
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001326 auto const buf_info = vk::BufferCreateInfo().setSize(sizeof(data)).setUsage(vk::BufferUsageFlagBits::eUniformBuffer);
1327 auto result = device.createBuffer(&buf_info, nullptr, &uniform_data.buf);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001328 VERIFY(result == vk::Result::eSuccess);
1329
1330 vk::MemoryRequirements mem_reqs;
1331 device.getBufferMemoryRequirements(uniform_data.buf, &mem_reqs);
1332
1333 uniform_data.mem_alloc.setAllocationSize(mem_reqs.size);
1334 uniform_data.mem_alloc.setMemoryTypeIndex(0);
1335
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001336 bool const pass = memory_type_from_properties(mem_reqs.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible |
1337 vk::MemoryPropertyFlagBits::eHostCoherent,
1338 &uniform_data.mem_alloc.memoryTypeIndex);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001339 VERIFY(pass);
1340
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001341 result = device.allocateMemory(&uniform_data.mem_alloc, nullptr, &(uniform_data.mem));
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001342 VERIFY(result == vk::Result::eSuccess);
1343
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001344 auto pData = device.mapMemory(uniform_data.mem, 0, uniform_data.mem_alloc.allocationSize, vk::MemoryMapFlags());
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001345 VERIFY(pData.result == vk::Result::eSuccess);
1346
1347 memcpy(pData.value, &data, sizeof data);
1348
1349 device.unmapMemory(uniform_data.mem);
1350
1351 result = device.bindBufferMemory(uniform_data.buf, uniform_data.mem, 0);
1352 VERIFY(result == vk::Result::eSuccess);
1353
1354 uniform_data.buffer_info.buffer = uniform_data.buf;
1355 uniform_data.buffer_info.offset = 0;
1356 uniform_data.buffer_info.range = sizeof(data);
1357 }
1358
Jeremy Hayes9d304782016-10-09 11:48:12 -06001359 void prepare_depth() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001360 depth.format = vk::Format::eD16Unorm;
1361
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001362 auto const image = vk::ImageCreateInfo()
1363 .setImageType(vk::ImageType::e2D)
1364 .setFormat(depth.format)
1365 .setExtent({(uint32_t)width, (uint32_t)height, 1})
1366 .setMipLevels(1)
1367 .setArrayLayers(1)
1368 .setSamples(vk::SampleCountFlagBits::e1)
1369 .setTiling(vk::ImageTiling::eOptimal)
1370 .setUsage(vk::ImageUsageFlagBits::eDepthStencilAttachment)
1371 .setSharingMode(vk::SharingMode::eExclusive)
1372 .setQueueFamilyIndexCount(0)
1373 .setPQueueFamilyIndices(nullptr)
1374 .setInitialLayout(vk::ImageLayout::eUndefined);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001375
1376 auto result = device.createImage(&image, nullptr, &depth.image);
1377 VERIFY(result == vk::Result::eSuccess);
1378
1379 vk::MemoryRequirements mem_reqs;
1380 device.getImageMemoryRequirements(depth.image, &mem_reqs);
1381
1382 depth.mem_alloc.setAllocationSize(mem_reqs.size);
1383 depth.mem_alloc.setMemoryTypeIndex(0);
1384
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001385 auto const pass =
1386 memory_type_from_properties(mem_reqs.memoryTypeBits, vk::MemoryPropertyFlagBits(0), &depth.mem_alloc.memoryTypeIndex);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001387 VERIFY(pass);
1388
1389 result = device.allocateMemory(&depth.mem_alloc, nullptr, &depth.mem);
1390 VERIFY(result == vk::Result::eSuccess);
1391
1392 result = device.bindImageMemory(depth.image, depth.mem, 0);
1393 VERIFY(result == vk::Result::eSuccess);
1394
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001395 auto const view = vk::ImageViewCreateInfo()
Jeremy Hayes9d304782016-10-09 11:48:12 -06001396 .setImage(depth.image)
1397 .setViewType(vk::ImageViewType::e2D)
1398 .setFormat(depth.format)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001399 .setSubresourceRange(vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1));
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001400 result = device.createImageView(&view, nullptr, &depth.view);
1401 VERIFY(result == vk::Result::eSuccess);
1402 }
1403
Jeremy Hayes9d304782016-10-09 11:48:12 -06001404 void prepare_descriptor_layout() {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001405 vk::DescriptorSetLayoutBinding const layout_bindings[2] = {vk::DescriptorSetLayoutBinding()
1406 .setBinding(0)
1407 .setDescriptorType(vk::DescriptorType::eUniformBuffer)
1408 .setDescriptorCount(1)
1409 .setStageFlags(vk::ShaderStageFlagBits::eVertex)
1410 .setPImmutableSamplers(nullptr),
1411 vk::DescriptorSetLayoutBinding()
1412 .setBinding(1)
1413 .setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
1414 .setDescriptorCount(texture_count)
1415 .setStageFlags(vk::ShaderStageFlagBits::eFragment)
1416 .setPImmutableSamplers(nullptr)};
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001417
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001418 auto const descriptor_layout = vk::DescriptorSetLayoutCreateInfo().setBindingCount(2).setPBindings(layout_bindings);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001419
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001420 auto result = device.createDescriptorSetLayout(&descriptor_layout, nullptr, &desc_layout);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001421 VERIFY(result == vk::Result::eSuccess);
1422
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001423 auto const pPipelineLayoutCreateInfo = vk::PipelineLayoutCreateInfo().setSetLayoutCount(1).setPSetLayouts(&desc_layout);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001424
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001425 result = device.createPipelineLayout(&pPipelineLayoutCreateInfo, nullptr, &pipeline_layout);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001426 VERIFY(result == vk::Result::eSuccess);
1427 }
1428
Jeremy Hayes9d304782016-10-09 11:48:12 -06001429 void prepare_descriptor_pool() {
1430 vk::DescriptorPoolSize const poolSizes[2] = {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001431 vk::DescriptorPoolSize().setType(vk::DescriptorType::eUniformBuffer).setDescriptorCount(1),
1432 vk::DescriptorPoolSize().setType(vk::DescriptorType::eCombinedImageSampler).setDescriptorCount(texture_count)};
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001433
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001434 auto const descriptor_pool = vk::DescriptorPoolCreateInfo().setMaxSets(1).setPoolSizeCount(2).setPPoolSizes(poolSizes);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001435
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001436 auto result = device.createDescriptorPool(&descriptor_pool, nullptr, &desc_pool);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001437 VERIFY(result == vk::Result::eSuccess);
1438 }
1439
Jeremy Hayes9d304782016-10-09 11:48:12 -06001440 void prepare_descriptor_set() {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001441 auto const alloc_info =
1442 vk::DescriptorSetAllocateInfo().setDescriptorPool(desc_pool).setDescriptorSetCount(1).setPSetLayouts(&desc_layout);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001443 auto result = device.allocateDescriptorSets(&alloc_info, &desc_set);
1444 VERIFY(result == vk::Result::eSuccess);
1445
1446 vk::DescriptorImageInfo tex_descs[texture_count];
Jeremy Hayes9d304782016-10-09 11:48:12 -06001447 for (uint32_t i = 0; i < texture_count; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001448 tex_descs[i].setSampler(textures[i].sampler);
1449 tex_descs[i].setImageView(textures[i].view);
1450 tex_descs[i].setImageLayout(vk::ImageLayout::eGeneral);
1451 }
1452
1453 vk::WriteDescriptorSet writes[2];
1454
1455 writes[0].setDstSet(desc_set);
1456 writes[0].setDescriptorCount(1);
1457 writes[0].setDescriptorType(vk::DescriptorType::eUniformBuffer);
1458 writes[0].setPBufferInfo(&uniform_data.buffer_info);
1459
1460 writes[1].setDstSet(desc_set);
1461 writes[1].setDstBinding(1);
1462 writes[1].setDescriptorCount(texture_count);
1463 writes[1].setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
1464 writes[1].setPImageInfo(tex_descs);
1465
1466 device.updateDescriptorSets(2, writes, 0, nullptr);
1467 }
1468
Jeremy Hayes9d304782016-10-09 11:48:12 -06001469 void prepare_framebuffers() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001470 vk::ImageView attachments[2];
1471 attachments[1] = depth.view;
1472
1473 auto const fb_info = vk::FramebufferCreateInfo()
Jeremy Hayes9d304782016-10-09 11:48:12 -06001474 .setRenderPass(render_pass)
1475 .setAttachmentCount(2)
1476 .setPAttachments(attachments)
1477 .setWidth((uint32_t)width)
1478 .setHeight((uint32_t)height)
1479 .setLayers(1);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001480
1481 framebuffers.reset(new vk::Framebuffer[swapchainImageCount]);
1482
Jeremy Hayes9d304782016-10-09 11:48:12 -06001483 for (uint32_t i = 0; i < swapchainImageCount; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001484 attachments[0] = buffers[i].view;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001485 auto const result = device.createFramebuffer(&fb_info, nullptr, &framebuffers[i]);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001486 VERIFY(result == vk::Result::eSuccess);
1487 }
1488 }
1489
Jeremy Hayes9d304782016-10-09 11:48:12 -06001490 vk::ShaderModule prepare_fs() {
Jeremy Hayese4080612016-10-09 13:48:31 -06001491 size_t size = 0;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001492 void *fragShaderCode = read_spv("cube-frag.spv", &size);
1493
1494 frag_shader_module = prepare_shader_module(fragShaderCode, size);
1495
1496 free(fragShaderCode);
1497
1498 return frag_shader_module;
1499 }
1500
Jeremy Hayes9d304782016-10-09 11:48:12 -06001501 void prepare_pipeline() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001502 vk::PipelineCacheCreateInfo const pipelineCacheInfo;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001503 auto result = device.createPipelineCache(&pipelineCacheInfo, nullptr, &pipelineCache);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001504 VERIFY(result == vk::Result::eSuccess);
1505
Jeremy Hayes9d304782016-10-09 11:48:12 -06001506 vk::PipelineShaderStageCreateInfo const shaderStageInfo[2] = {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001507 vk::PipelineShaderStageCreateInfo().setStage(vk::ShaderStageFlagBits::eVertex).setModule(prepare_vs()).setPName("main"),
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001508 vk::PipelineShaderStageCreateInfo()
1509 .setStage(vk::ShaderStageFlagBits::eFragment)
1510 .setModule(prepare_fs())
Jeremy Hayes9d304782016-10-09 11:48:12 -06001511 .setPName("main")};
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001512
1513 vk::PipelineVertexInputStateCreateInfo const vertexInputInfo;
1514
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001515 auto const inputAssemblyInfo = vk::PipelineInputAssemblyStateCreateInfo().setTopology(vk::PrimitiveTopology::eTriangleList);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001516
1517 // TODO: Where are pViewports and pScissors set?
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001518 auto const viewportInfo = vk::PipelineViewportStateCreateInfo().setViewportCount(1).setScissorCount(1);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001519
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001520 auto const rasterizationInfo = vk::PipelineRasterizationStateCreateInfo()
1521 .setDepthClampEnable(VK_FALSE)
1522 .setRasterizerDiscardEnable(VK_FALSE)
1523 .setPolygonMode(vk::PolygonMode::eFill)
1524 .setCullMode(vk::CullModeFlagBits::eBack)
1525 .setFrontFace(vk::FrontFace::eCounterClockwise)
1526 .setDepthBiasEnable(VK_FALSE)
1527 .setLineWidth(1.0f);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001528
1529 auto const multisampleInfo = vk::PipelineMultisampleStateCreateInfo();
1530
1531 auto const stencilOp = vk::StencilOpState()
Jeremy Hayes9d304782016-10-09 11:48:12 -06001532 .setFailOp(vk::StencilOp::eKeep)
1533 .setPassOp(vk::StencilOp::eKeep)
1534 .setCompareOp(vk::CompareOp::eAlways);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001535
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001536 auto const depthStencilInfo = vk::PipelineDepthStencilStateCreateInfo()
1537 .setDepthTestEnable(VK_TRUE)
1538 .setDepthWriteEnable(VK_TRUE)
1539 .setDepthCompareOp(vk::CompareOp::eLessOrEqual)
1540 .setDepthBoundsTestEnable(VK_FALSE)
1541 .setStencilTestEnable(VK_FALSE)
1542 .setFront(stencilOp)
1543 .setBack(stencilOp);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001544
Jeremy Hayes9d304782016-10-09 11:48:12 -06001545 vk::PipelineColorBlendAttachmentState const colorBlendAttachments[1] = {
1546 vk::PipelineColorBlendAttachmentState().setColorWriteMask(
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001547 vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB |
Jeremy Hayes9d304782016-10-09 11:48:12 -06001548 vk::ColorComponentFlagBits::eA)};
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001549
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001550 auto const colorBlendInfo =
1551 vk::PipelineColorBlendStateCreateInfo().setAttachmentCount(1).setPAttachments(colorBlendAttachments);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001552
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001553 vk::DynamicState const dynamicStates[2] = {vk::DynamicState::eViewport, vk::DynamicState::eScissor};
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001554
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001555 auto const dynamicStateInfo = vk::PipelineDynamicStateCreateInfo().setPDynamicStates(dynamicStates).setDynamicStateCount(2);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001556
1557 auto const pipeline = vk::GraphicsPipelineCreateInfo()
Jeremy Hayes9d304782016-10-09 11:48:12 -06001558 .setStageCount(2)
1559 .setPStages(shaderStageInfo)
1560 .setPVertexInputState(&vertexInputInfo)
1561 .setPInputAssemblyState(&inputAssemblyInfo)
1562 .setPViewportState(&viewportInfo)
1563 .setPRasterizationState(&rasterizationInfo)
1564 .setPMultisampleState(&multisampleInfo)
1565 .setPDepthStencilState(&depthStencilInfo)
1566 .setPColorBlendState(&colorBlendInfo)
1567 .setPDynamicState(&dynamicStateInfo)
1568 .setLayout(pipeline_layout)
1569 .setRenderPass(render_pass);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001570
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001571 result = device.createGraphicsPipelines(pipelineCache, 1, &pipeline, nullptr, &this->pipeline);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001572 VERIFY(result == vk::Result::eSuccess);
1573
1574 device.destroyShaderModule(frag_shader_module, nullptr);
1575 device.destroyShaderModule(vert_shader_module, nullptr);
1576 }
1577
Jeremy Hayes9d304782016-10-09 11:48:12 -06001578 void prepare_render_pass() {
Jeremy Hayes522bc652016-10-25 16:12:09 -06001579 // The initial layout for the color and depth attachments will be LAYOUT_UNDEFINED
1580 // because at the start of the renderpass, we don't care about their contents.
1581 // At the start of the subpass, the color attachment's layout will be transitioned
1582 // to LAYOUT_COLOR_ATTACHMENT_OPTIMAL and the depth stencil attachment's layout
1583 // will be transitioned to LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL. At the end of
1584 // the renderpass, the color attachment's layout will be transitioned to
1585 // LAYOUT_PRESENT_SRC_KHR to be ready to present. This is all done as part of
1586 // the renderpass, no barriers are necessary.
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001587 const vk::AttachmentDescription attachments[2] = {vk::AttachmentDescription()
1588 .setFormat(format)
1589 .setSamples(vk::SampleCountFlagBits::e1)
1590 .setLoadOp(vk::AttachmentLoadOp::eClear)
1591 .setStoreOp(vk::AttachmentStoreOp::eStore)
1592 .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
1593 .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
1594 .setInitialLayout(vk::ImageLayout::eUndefined)
1595 .setFinalLayout(vk::ImageLayout::ePresentSrcKHR),
1596 vk::AttachmentDescription()
1597 .setFormat(depth.format)
1598 .setSamples(vk::SampleCountFlagBits::e1)
1599 .setLoadOp(vk::AttachmentLoadOp::eClear)
1600 .setStoreOp(vk::AttachmentStoreOp::eDontCare)
1601 .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
1602 .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
1603 .setInitialLayout(vk::ImageLayout::eUndefined)
1604 .setFinalLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal)};
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001605
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001606 auto const color_reference = vk::AttachmentReference().setAttachment(0).setLayout(vk::ImageLayout::eColorAttachmentOptimal);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001607
Jeremy Hayes9d304782016-10-09 11:48:12 -06001608 auto const depth_reference =
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001609 vk::AttachmentReference().setAttachment(1).setLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001610
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001611 auto const subpass = vk::SubpassDescription()
1612 .setPipelineBindPoint(vk::PipelineBindPoint::eGraphics)
1613 .setInputAttachmentCount(0)
1614 .setPInputAttachments(nullptr)
1615 .setColorAttachmentCount(1)
1616 .setPColorAttachments(&color_reference)
1617 .setPResolveAttachments(nullptr)
1618 .setPDepthStencilAttachment(&depth_reference)
1619 .setPreserveAttachmentCount(0)
1620 .setPPreserveAttachments(nullptr);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001621
1622 auto const rp_info = vk::RenderPassCreateInfo()
Jeremy Hayes9d304782016-10-09 11:48:12 -06001623 .setAttachmentCount(2)
1624 .setPAttachments(attachments)
1625 .setSubpassCount(1)
1626 .setPSubpasses(&subpass)
1627 .setDependencyCount(0)
1628 .setPDependencies(nullptr);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001629
1630 auto result = device.createRenderPass(&rp_info, nullptr, &render_pass);
1631 VERIFY(result == vk::Result::eSuccess);
1632 }
1633
Jeremy Hayes9d304782016-10-09 11:48:12 -06001634 vk::ShaderModule prepare_shader_module(const void *code, size_t size) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001635 auto const moduleCreateInfo = vk::ShaderModuleCreateInfo().setCodeSize(size).setPCode((uint32_t const *)code);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001636
1637 vk::ShaderModule module;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001638 auto result = device.createShaderModule(&moduleCreateInfo, nullptr, &module);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001639 VERIFY(result == vk::Result::eSuccess);
1640
1641 return module;
1642 }
1643
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001644 void prepare_texture_image(const char *filename, texture_object *tex_obj, vk::ImageTiling tiling, vk::ImageUsageFlags usage,
Jeremy Hayes9d304782016-10-09 11:48:12 -06001645 vk::MemoryPropertyFlags required_props) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001646 int32_t tex_width;
1647 int32_t tex_height;
Jeremy Hayes9d304782016-10-09 11:48:12 -06001648 if (!loadTexture(filename, nullptr, nullptr, &tex_width, &tex_height)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001649 ERR_EXIT("Failed to load textures", "Load Texture Failure");
1650 }
1651
1652 tex_obj->tex_width = tex_width;
1653 tex_obj->tex_height = tex_height;
1654
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001655 auto const image_create_info = vk::ImageCreateInfo()
1656 .setImageType(vk::ImageType::e2D)
1657 .setFormat(vk::Format::eR8G8B8A8Unorm)
1658 .setExtent({(uint32_t)tex_width, (uint32_t)tex_height, 1})
1659 .setMipLevels(1)
1660 .setArrayLayers(1)
1661 .setSamples(vk::SampleCountFlagBits::e1)
1662 .setTiling(tiling)
1663 .setUsage(usage)
1664 .setSharingMode(vk::SharingMode::eExclusive)
1665 .setQueueFamilyIndexCount(0)
1666 .setPQueueFamilyIndices(nullptr)
1667 .setInitialLayout(vk::ImageLayout::ePreinitialized);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001668
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001669 auto result = device.createImage(&image_create_info, nullptr, &tex_obj->image);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001670 VERIFY(result == vk::Result::eSuccess);
1671
1672 vk::MemoryRequirements mem_reqs;
1673 device.getImageMemoryRequirements(tex_obj->image, &mem_reqs);
1674
1675 tex_obj->mem_alloc.setAllocationSize(mem_reqs.size);
1676 tex_obj->mem_alloc.setMemoryTypeIndex(0);
1677
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001678 auto pass = memory_type_from_properties(mem_reqs.memoryTypeBits, required_props, &tex_obj->mem_alloc.memoryTypeIndex);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001679 VERIFY(pass == true);
1680
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001681 result = device.allocateMemory(&tex_obj->mem_alloc, nullptr, &(tex_obj->mem));
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001682 VERIFY(result == vk::Result::eSuccess);
1683
1684 result = device.bindImageMemory(tex_obj->image, tex_obj->mem, 0);
1685 VERIFY(result == vk::Result::eSuccess);
1686
Jeremy Hayes9d304782016-10-09 11:48:12 -06001687 if (required_props & vk::MemoryPropertyFlagBits::eHostVisible) {
1688 auto const subres =
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001689 vk::ImageSubresource().setAspectMask(vk::ImageAspectFlagBits::eColor).setMipLevel(0).setArrayLayer(0);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001690 vk::SubresourceLayout layout;
1691 device.getImageSubresourceLayout(tex_obj->image, &subres, &layout);
1692
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001693 auto data = device.mapMemory(tex_obj->mem, 0, tex_obj->mem_alloc.allocationSize);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001694 VERIFY(data.result == vk::Result::eSuccess);
1695
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001696 if (!loadTexture(filename, (uint8_t *)data.value, &layout, &tex_width, &tex_height)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001697 fprintf(stderr, "Error loading texture: %s\n", filename);
1698 }
1699
1700 device.unmapMemory(tex_obj->mem);
1701 }
1702
1703 tex_obj->imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001704 }
1705
Jeremy Hayes9d304782016-10-09 11:48:12 -06001706 void prepare_textures() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001707 vk::Format const tex_format = vk::Format::eR8G8B8A8Unorm;
1708 vk::FormatProperties props;
1709 gpu.getFormatProperties(tex_format, &props);
1710
Jeremy Hayes9d304782016-10-09 11:48:12 -06001711 for (uint32_t i = 0; i < texture_count; i++) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001712 if ((props.linearTilingFeatures & vk::FormatFeatureFlagBits::eSampledImage) && !use_staging_buffer) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001713 /* Device can texture using linear textures */
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001714 prepare_texture_image(tex_files[i], &textures[i], vk::ImageTiling::eLinear, vk::ImageUsageFlagBits::eSampled,
1715 vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
Jeremy Hayesb0c86fa2016-10-25 17:32:23 -06001716 // Nothing in the pipeline needs to be complete to start, and don't allow fragment
1717 // shader to run until layout transition completes
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001718 set_image_layout(textures[i].image, vk::ImageAspectFlagBits::eColor, vk::ImageLayout::ePreinitialized,
1719 textures[i].imageLayout, vk::AccessFlagBits::eHostWrite, vk::PipelineStageFlagBits::eTopOfPipe,
Jeremy Hayesb0c86fa2016-10-25 17:32:23 -06001720 vk::PipelineStageFlagBits::eFragmentShader);
Jeremy Hayes1db0cee2016-11-16 14:15:25 -07001721 staging_texture.image = vk::Image();
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001722 } else if (props.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImage) {
Jeremy Hayes1db0cee2016-11-16 14:15:25 -07001723 /* Must use staging buffer to copy linear texture to optimized */
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001724
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001725 prepare_texture_image(tex_files[i], &staging_texture, vk::ImageTiling::eLinear,
1726 vk::ImageUsageFlagBits::eTransferSrc,
1727 vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001728
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001729 prepare_texture_image(tex_files[i], &textures[i], vk::ImageTiling::eOptimal,
1730 vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
Jeremy Hayes9d304782016-10-09 11:48:12 -06001731 vk::MemoryPropertyFlagBits::eDeviceLocal);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001732
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001733 set_image_layout(staging_texture.image, vk::ImageAspectFlagBits::eColor, vk::ImageLayout::ePreinitialized,
1734 vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits::eHostWrite,
1735 vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001736
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001737 set_image_layout(textures[i].image, vk::ImageAspectFlagBits::eColor, vk::ImageLayout::ePreinitialized,
1738 vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits::eHostWrite,
1739 vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001740
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001741 auto const subresource = vk::ImageSubresourceLayers()
1742 .setAspectMask(vk::ImageAspectFlagBits::eColor)
1743 .setMipLevel(0)
1744 .setBaseArrayLayer(0)
1745 .setLayerCount(1);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001746
Jeremy Hayes9d304782016-10-09 11:48:12 -06001747 auto const copy_region =
1748 vk::ImageCopy()
1749 .setSrcSubresource(subresource)
1750 .setSrcOffset({0, 0, 0})
1751 .setDstSubresource(subresource)
1752 .setDstOffset({0, 0, 0})
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001753 .setExtent({(uint32_t)staging_texture.tex_width, (uint32_t)staging_texture.tex_height, 1});
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001754
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001755 cmd.copyImage(staging_texture.image, vk::ImageLayout::eTransferSrcOptimal, textures[i].image,
1756 vk::ImageLayout::eTransferDstOptimal, 1, &copy_region);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001757
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001758 set_image_layout(textures[i].image, vk::ImageAspectFlagBits::eColor, vk::ImageLayout::eTransferDstOptimal,
1759 textures[i].imageLayout, vk::AccessFlagBits::eTransferWrite, vk::PipelineStageFlagBits::eTransfer,
Jeremy Hayesb0c86fa2016-10-25 17:32:23 -06001760 vk::PipelineStageFlagBits::eFragmentShader);
Jeremy Hayes9d304782016-10-09 11:48:12 -06001761 } else {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001762 assert(!"No support for R8G8B8A8_UNORM as texture image format");
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001763 }
1764
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001765 auto const samplerInfo = vk::SamplerCreateInfo()
1766 .setMagFilter(vk::Filter::eNearest)
1767 .setMinFilter(vk::Filter::eNearest)
1768 .setMipmapMode(vk::SamplerMipmapMode::eNearest)
1769 .setAddressModeU(vk::SamplerAddressMode::eClampToEdge)
1770 .setAddressModeV(vk::SamplerAddressMode::eClampToEdge)
1771 .setAddressModeW(vk::SamplerAddressMode::eClampToEdge)
1772 .setMipLodBias(0.0f)
1773 .setAnisotropyEnable(VK_FALSE)
1774 .setMaxAnisotropy(1)
1775 .setCompareEnable(VK_FALSE)
1776 .setCompareOp(vk::CompareOp::eNever)
1777 .setMinLod(0.0f)
1778 .setMaxLod(0.0f)
1779 .setBorderColor(vk::BorderColor::eFloatOpaqueWhite)
1780 .setUnnormalizedCoordinates(VK_FALSE);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001781
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001782 auto result = device.createSampler(&samplerInfo, nullptr, &textures[i].sampler);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001783 VERIFY(result == vk::Result::eSuccess);
1784
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001785 auto const viewInfo = vk::ImageViewCreateInfo()
1786 .setImage(textures[i].image)
1787 .setViewType(vk::ImageViewType::e2D)
1788 .setFormat(tex_format)
1789 .setSubresourceRange(vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001790
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001791 result = device.createImageView(&viewInfo, nullptr, &textures[i].view);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001792 VERIFY(result == vk::Result::eSuccess);
1793 }
1794 }
1795
Jeremy Hayes9d304782016-10-09 11:48:12 -06001796 vk::ShaderModule prepare_vs() {
Jeremy Hayes9ca525c2016-10-09 12:21:06 -06001797 size_t size = 0;
Jeremy Hayes9d304782016-10-09 11:48:12 -06001798 void *vertShaderCode = read_spv("cube-vert.spv", &size);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001799
1800 vert_shader_module = prepare_shader_module(vertShaderCode, size);
1801
1802 free(vertShaderCode);
1803
1804 return vert_shader_module;
1805 }
1806
Jeremy Hayes9d304782016-10-09 11:48:12 -06001807 char *read_spv(const char *filename, size_t *psize) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001808 FILE *fp = fopen(filename, "rb");
Jeremy Hayes9d304782016-10-09 11:48:12 -06001809 if (!fp) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001810 return nullptr;
1811 }
1812
1813 fseek(fp, 0L, SEEK_END);
1814 long int size = ftell(fp);
1815
1816 fseek(fp, 0L, SEEK_SET);
1817
1818 void *shader_code = malloc(size);
1819 size_t retval = fread(shader_code, size, 1, fp);
1820 VERIFY(retval == 1);
1821
1822 *psize = size;
1823
1824 fclose(fp);
1825
Jeremy Hayes9d304782016-10-09 11:48:12 -06001826 return (char *)shader_code;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001827 }
1828
Jeremy Hayes9d304782016-10-09 11:48:12 -06001829 void resize() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001830 uint32_t i;
1831
1832 // Don't react to resize until after first initialization.
Jeremy Hayes9d304782016-10-09 11:48:12 -06001833 if (!prepared) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001834 return;
1835 }
1836
Jeremy Hayes9d304782016-10-09 11:48:12 -06001837 // In order to properly resize the window, we must re-create the
1838 // swapchain
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001839 // AND redo the command buffers, etc.
1840 //
1841 // First, perform part of the cleanup() function:
1842 prepared = false;
1843 auto result = device.waitIdle();
1844 VERIFY(result == vk::Result::eSuccess);
1845
Jeremy Hayes9d304782016-10-09 11:48:12 -06001846 for (i = 0; i < swapchainImageCount; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001847 device.destroyFramebuffer(framebuffers[i], nullptr);
1848 }
1849
1850 device.destroyDescriptorPool(desc_pool, nullptr);
1851
1852 device.destroyPipeline(pipeline, nullptr);
1853 device.destroyPipelineCache(pipelineCache, nullptr);
1854 device.destroyRenderPass(render_pass, nullptr);
1855 device.destroyPipelineLayout(pipeline_layout, nullptr);
1856 device.destroyDescriptorSetLayout(desc_layout, nullptr);
1857
Jeremy Hayes9d304782016-10-09 11:48:12 -06001858 for (i = 0; i < texture_count; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001859 device.destroyImageView(textures[i].view, nullptr);
1860 device.destroyImage(textures[i].image, nullptr);
1861 device.freeMemory(textures[i].mem, nullptr);
1862 device.destroySampler(textures[i].sampler, nullptr);
1863 }
1864
1865 device.destroyImageView(depth.view, nullptr);
1866 device.destroyImage(depth.image, nullptr);
1867 device.freeMemory(depth.mem, nullptr);
1868
1869 device.destroyBuffer(uniform_data.buf, nullptr);
1870 device.freeMemory(uniform_data.mem, nullptr);
1871
Jeremy Hayes9d304782016-10-09 11:48:12 -06001872 for (i = 0; i < swapchainImageCount; i++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001873 device.destroyImageView(buffers[i].view, nullptr);
1874 device.freeCommandBuffers(cmd_pool, 1, &buffers[i].cmd);
1875 }
1876
1877 device.destroyCommandPool(cmd_pool, nullptr);
Jeremy Hayes9d304782016-10-09 11:48:12 -06001878 if (separate_present_queue) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001879 device.destroyCommandPool(present_cmd_pool, nullptr);
1880 }
1881
Jeremy Hayes9d304782016-10-09 11:48:12 -06001882 // Second, re-perform the prepare() function, which will re-create the
1883 // swapchain.
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001884 prepare();
1885 }
1886
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001887 void set_image_layout(vk::Image image, vk::ImageAspectFlags aspectMask, vk::ImageLayout oldLayout, vk::ImageLayout newLayout,
1888 vk::AccessFlags srcAccessMask, vk::PipelineStageFlags src_stages, vk::PipelineStageFlags dest_stages) {
Jeremy Hayes233130a2016-11-16 13:42:08 -07001889 assert(cmd);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001890
Jeremy Hayes9d304782016-10-09 11:48:12 -06001891 auto DstAccessMask = [](vk::ImageLayout const &layout) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001892 vk::AccessFlags flags;
1893
Jeremy Hayes9d304782016-10-09 11:48:12 -06001894 switch (layout) {
1895 case vk::ImageLayout::eTransferDstOptimal:
1896 // Make sure anything that was copying from this image has
1897 // completed
Jeremy Hayesc2409a22016-10-25 17:02:33 -06001898 flags = vk::AccessFlagBits::eTransferWrite;
Jeremy Hayes9d304782016-10-09 11:48:12 -06001899 break;
1900 case vk::ImageLayout::eColorAttachmentOptimal:
1901 flags = vk::AccessFlagBits::eColorAttachmentWrite;
1902 break;
1903 case vk::ImageLayout::eDepthStencilAttachmentOptimal:
1904 flags = vk::AccessFlagBits::eDepthStencilAttachmentWrite;
1905 break;
1906 case vk::ImageLayout::eShaderReadOnlyOptimal:
1907 // Make sure any Copy or CPU writes to image are flushed
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001908 flags = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eInputAttachmentRead;
Jeremy Hayes9d304782016-10-09 11:48:12 -06001909 break;
Jeremy Hayesc2409a22016-10-25 17:02:33 -06001910 case vk::ImageLayout::eTransferSrcOptimal:
1911 flags = vk::AccessFlagBits::eTransferRead;
1912 break;
Jeremy Hayes9d304782016-10-09 11:48:12 -06001913 case vk::ImageLayout::ePresentSrcKHR:
1914 flags = vk::AccessFlagBits::eMemoryRead;
1915 break;
1916 default:
1917 break;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001918 }
1919
1920 return flags;
1921 };
1922
1923 auto const barrier = vk::ImageMemoryBarrier()
Jeremy Hayes9d304782016-10-09 11:48:12 -06001924 .setSrcAccessMask(srcAccessMask)
1925 .setDstAccessMask(DstAccessMask(newLayout))
1926 .setOldLayout(oldLayout)
1927 .setNewLayout(newLayout)
1928 .setSrcQueueFamilyIndex(0)
1929 .setDstQueueFamilyIndex(0)
1930 .setImage(image)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001931 .setSubresourceRange(vk::ImageSubresourceRange(aspectMask, 0, 1, 0, 1));
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001932
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001933 cmd.pipelineBarrier(src_stages, dest_stages, vk::DependencyFlagBits(), 0, nullptr, 0, nullptr, 1, &barrier);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001934 }
1935
Jeremy Hayes9d304782016-10-09 11:48:12 -06001936 void update_data_buffer() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001937 mat4x4 VP;
1938 mat4x4_mul(VP, projection_matrix, view_matrix);
1939
Karl Schultz6ddf1e02017-01-04 10:31:20 -07001940 // Rotate around the Y axis
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001941 mat4x4 Model;
1942 mat4x4_dup(Model, model_matrix);
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001943 mat4x4_rotate(model_matrix, Model, 0.0f, 1.0f, 0.0f, (float)degreesToRadians(spin_angle));
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001944
1945 mat4x4 MVP;
1946 mat4x4_mul(MVP, VP, model_matrix);
1947
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001948 auto data = device.mapMemory(uniform_data.mem, 0, uniform_data.mem_alloc.allocationSize, vk::MemoryMapFlags());
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001949 VERIFY(data.result == vk::Result::eSuccess);
1950
1951 memcpy(data.value, (const void *)&MVP[0][0], sizeof(MVP));
1952
1953 device.unmapMemory(uniform_data.mem);
1954 }
1955
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07001956 bool loadTexture(const char *filename, uint8_t *rgba_data, vk::SubresourceLayout *layout, int32_t *width, int32_t *height) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001957 FILE *fPtr = fopen(filename, "rb");
Jeremy Hayes9d304782016-10-09 11:48:12 -06001958 if (!fPtr) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001959 return false;
1960 }
1961
1962 char header[256];
Jeremy Hayes9d304782016-10-09 11:48:12 -06001963 char *cPtr = fgets(header, 256, fPtr); // P6
1964 if (cPtr == nullptr || strncmp(header, "P6\n", 3)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001965 fclose(fPtr);
1966 return false;
1967 }
1968
Jeremy Hayes9d304782016-10-09 11:48:12 -06001969 do {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001970 cPtr = fgets(header, 256, fPtr);
Jeremy Hayes9d304782016-10-09 11:48:12 -06001971 if (cPtr == nullptr) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001972 fclose(fPtr);
1973 return false;
1974 }
Jeremy Hayes9d304782016-10-09 11:48:12 -06001975 } while (!strncmp(header, "#", 1));
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001976
1977 sscanf(header, "%u %u", width, height);
Jeremy Hayes9d304782016-10-09 11:48:12 -06001978 if (rgba_data == nullptr) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001979 fclose(fPtr);
1980 return true;
1981 }
1982
Jeremy Hayes9d304782016-10-09 11:48:12 -06001983 char *result = fgets(header, 256, fPtr); // Format
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001984 VERIFY(result != nullptr);
Jeremy Hayes9d304782016-10-09 11:48:12 -06001985 if (cPtr == nullptr || strncmp(header, "255\n", 3)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001986 fclose(fPtr);
1987 return false;
1988 }
1989
Jeremy Hayes9d304782016-10-09 11:48:12 -06001990 for (int y = 0; y < *height; y++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001991 uint8_t *rowPtr = rgba_data;
1992
Jeremy Hayes9d304782016-10-09 11:48:12 -06001993 for (int x = 0; x < *width; x++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06001994 size_t s = fread(rowPtr, 3, 1, fPtr);
1995 (void)s;
1996 rowPtr[3] = 255; /* Alpha of 1 */
1997 rowPtr += 4;
1998 }
1999
2000 rgba_data += layout->rowPitch;
2001 }
2002
2003 fclose(fPtr);
2004 return true;
2005 }
2006
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002007 bool memory_type_from_properties(uint32_t typeBits, vk::MemoryPropertyFlags requirements_mask, uint32_t *typeIndex) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002008 // Search memtypes to find first index with those properties
Jeremy Hayes9d304782016-10-09 11:48:12 -06002009 for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
2010 if ((typeBits & 1) == 1) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002011 // Type is available, does it match user properties?
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002012 if ((memory_properties.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002013 *typeIndex = i;
2014 return true;
2015 }
2016 }
2017 typeBits >>= 1;
2018 }
2019
2020 // No memory types matched, return failure
2021 return false;
2022 }
2023
2024#if defined(VK_USE_PLATFORM_WIN32_KHR)
Jeremy Hayes9d304782016-10-09 11:48:12 -06002025 void run() {
2026 if (!prepared) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002027 return;
2028 }
2029
2030 update_data_buffer();
2031 draw();
2032 curFrame++;
2033
Jeremy Hayes9d304782016-10-09 11:48:12 -06002034 if (frameCount != INT_MAX && curFrame == frameCount) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002035 PostQuitMessage(validation_error);
2036 }
2037 }
2038
Jeremy Hayes9d304782016-10-09 11:48:12 -06002039 void create_window() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002040 WNDCLASSEX win_class;
2041
2042 // Initialize the window class structure:
2043 win_class.cbSize = sizeof(WNDCLASSEX);
2044 win_class.style = CS_HREDRAW | CS_VREDRAW;
2045 win_class.lpfnWndProc = WndProc;
2046 win_class.cbClsExtra = 0;
2047 win_class.cbWndExtra = 0;
2048 win_class.hInstance = connection; // hInstance
2049 win_class.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
2050 win_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
2051 win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
2052 win_class.lpszMenuName = nullptr;
2053 win_class.lpszClassName = name;
2054 win_class.hIconSm = LoadIcon(nullptr, IDI_WINLOGO);
2055
2056 // Register window class:
Jeremy Hayes9d304782016-10-09 11:48:12 -06002057 if (!RegisterClassEx(&win_class)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002058 // It didn't work, so try to give a useful error:
2059 printf("Unexpected error trying to start the application!\n");
2060 fflush(stdout);
2061 exit(1);
2062 }
2063
2064 // Create window with the registered class:
Mark Lobodzinski1f2c7e62016-10-10 14:05:36 -06002065 RECT wr = {0, 0, static_cast<LONG>(width), static_cast<LONG>(height)};
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002066 AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
2067 window = CreateWindowEx(0,
Jeremy Hayes9d304782016-10-09 11:48:12 -06002068 name, // class name
2069 name, // app name
2070 WS_OVERLAPPEDWINDOW | // window style
2071 WS_VISIBLE | WS_SYSMENU,
2072 100, 100, // x/y coords
2073 wr.right - wr.left, // width
2074 wr.bottom - wr.top, // height
2075 nullptr, // handle to parent
2076 nullptr, // handle to menu
2077 connection, // hInstance
2078 nullptr); // no extra parameters
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002079
Jeremy Hayes9d304782016-10-09 11:48:12 -06002080 if (!window) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002081 // It didn't work, so try to give a useful error:
2082 printf("Cannot create a window in which to draw!\n");
2083 fflush(stdout);
2084 exit(1);
2085 }
2086
Jeremy Hayes9d304782016-10-09 11:48:12 -06002087 // Window client area size must be at least 1 pixel high, to prevent
2088 // crash.
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002089 minsize.x = GetSystemMetrics(SM_CXMINTRACK);
Jeremy Hayes9d304782016-10-09 11:48:12 -06002090 minsize.y = GetSystemMetrics(SM_CYMINTRACK) + 1;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002091 }
Tony Barbour153cb062016-12-07 13:43:36 -07002092#elif defined(VK_USE_PLATFORM_XLIB_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002093
Jeremy Hayes9d304782016-10-09 11:48:12 -06002094 void create_xlib_window() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002095 display = XOpenDisplay(nullptr);
2096 long visualMask = VisualScreenMask;
2097 int numberOfVisuals;
Jeremy Hayes9d304782016-10-09 11:48:12 -06002098 XVisualInfo vInfoTemplate = {};
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002099 vInfoTemplate.screen = DefaultScreen(display);
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002100 XVisualInfo *visualInfo = XGetVisualInfo(display, visualMask, &vInfoTemplate, &numberOfVisuals);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002101
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002102 Colormap colormap = XCreateColormap(display, RootWindow(display, vInfoTemplate.screen), visualInfo->visual, AllocNone);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002103
Jeremy Hayes9d304782016-10-09 11:48:12 -06002104 XSetWindowAttributes windowAttributes = {};
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002105 windowAttributes.colormap = colormap;
2106 windowAttributes.background_pixel = 0xFFFFFFFF;
2107 windowAttributes.border_pixel = 0;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002108 windowAttributes.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002109
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002110 xlib_window = XCreateWindow(display, RootWindow(display, vInfoTemplate.screen), 0, 0, width, height, 0, visualInfo->depth,
2111 InputOutput, visualInfo->visual, CWBackPixel | CWBorderPixel | CWEventMask | CWColormap,
2112 &windowAttributes);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002113
2114 XSelectInput(display, xlib_window, ExposureMask | KeyPressMask);
2115 XMapWindow(display, xlib_window);
2116 XFlush(display);
2117 xlib_wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
2118 }
2119
Jeremy Hayes9d304782016-10-09 11:48:12 -06002120 void handle_xlib_event(const XEvent *event) {
2121 switch (event->type) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002122 case ClientMessage:
Jeremy Hayes9d304782016-10-09 11:48:12 -06002123 if ((Atom)event->xclient.data.l[0] == xlib_wm_delete_window) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002124 quit = true;
2125 }
2126 break;
2127 case KeyPress:
Jeremy Hayes9d304782016-10-09 11:48:12 -06002128 switch (event->xkey.keycode) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002129 case 0x9: // Escape
2130 quit = true;
2131 break;
2132 case 0x71: // left arrow key
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002133 spin_angle -= spin_increment;
2134 break;
Karl Schultz6ddf1e02017-01-04 10:31:20 -07002135 case 0x72: // right arrow key
2136 spin_angle += spin_increment;
2137 break;
2138 case 0x41: // space bar
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002139 pause = !pause;
2140 break;
2141 }
2142 break;
2143 case ConfigureNotify:
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002144 if (((int32_t)width != event->xconfigure.width) || ((int32_t)height != event->xconfigure.height)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002145 width = event->xconfigure.width;
2146 height = event->xconfigure.height;
2147 resize();
2148 }
2149 break;
2150 default:
2151 break;
2152 }
2153 }
2154
Jeremy Hayes9d304782016-10-09 11:48:12 -06002155 void run_xlib() {
2156 while (!quit) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002157 XEvent event;
2158
Jeremy Hayes9d304782016-10-09 11:48:12 -06002159 if (pause) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002160 XNextEvent(display, &event);
2161 handle_xlib_event(&event);
Karl Schultz6ddf1e02017-01-04 10:31:20 -07002162 }
2163 while (XPending(display) > 0) {
2164 XNextEvent(display, &event);
2165 handle_xlib_event(&event);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002166 }
2167
2168 update_data_buffer();
2169 draw();
2170 curFrame++;
2171
Jeremy Hayes9d304782016-10-09 11:48:12 -06002172 if (frameCount != UINT32_MAX && curFrame == frameCount) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002173 quit = true;
2174 }
2175 }
2176 }
Tony Barbour153cb062016-12-07 13:43:36 -07002177#elif defined(VK_USE_PLATFORM_XCB_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002178
Jeremy Hayes9d304782016-10-09 11:48:12 -06002179 void handle_xcb_event(const xcb_generic_event_t *event) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002180 uint8_t event_code = event->response_type & 0x7f;
Jeremy Hayes9d304782016-10-09 11:48:12 -06002181 switch (event_code) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002182 case XCB_EXPOSE:
2183 // TODO: Resize window
2184 break;
2185 case XCB_CLIENT_MESSAGE:
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002186 if ((*(xcb_client_message_event_t *)event).data.data32[0] == (*atom_wm_delete_window).atom) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002187 quit = true;
2188 }
2189 break;
Jeremy Hayes9d304782016-10-09 11:48:12 -06002190 case XCB_KEY_RELEASE: {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002191 const xcb_key_release_event_t *key = (const xcb_key_release_event_t *)event;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002192
Jeremy Hayes9d304782016-10-09 11:48:12 -06002193 switch (key->detail) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002194 case 0x9: // Escape
2195 quit = true;
2196 break;
2197 case 0x71: // left arrow key
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002198 spin_angle -= spin_increment;
2199 break;
Karl Schultz6ddf1e02017-01-04 10:31:20 -07002200 case 0x72: // right arrow key
2201 spin_angle += spin_increment;
2202 break;
2203 case 0x41: // space bar
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002204 pause = !pause;
2205 break;
2206 }
2207 } break;
Jeremy Hayes9d304782016-10-09 11:48:12 -06002208 case XCB_CONFIGURE_NOTIFY: {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002209 const xcb_configure_notify_event_t *cfg = (const xcb_configure_notify_event_t *)event;
Jeremy Hayes9d304782016-10-09 11:48:12 -06002210 if ((width != cfg->width) || (height != cfg->height)) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002211 width = cfg->width;
2212 height = cfg->height;
2213 resize();
2214 }
2215 } break;
2216 default:
2217 break;
2218 }
2219 }
2220
Jeremy Hayes9d304782016-10-09 11:48:12 -06002221 void run_xcb() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002222 xcb_flush(connection);
2223
Jeremy Hayes9d304782016-10-09 11:48:12 -06002224 while (!quit) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002225 xcb_generic_event_t *event;
2226
Jeremy Hayes9d304782016-10-09 11:48:12 -06002227 if (pause) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002228 event = xcb_wait_for_event(connection);
Jeremy Hayes9d304782016-10-09 11:48:12 -06002229 } else {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002230 event = xcb_poll_for_event(connection);
Karl Schultz6ddf1e02017-01-04 10:31:20 -07002231 }
2232 while (event) {
2233 handle_xcb_event(event);
2234 free(event);
2235 event = xcb_poll_for_event(connection);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002236 }
2237
2238 update_data_buffer();
2239 draw();
2240 curFrame++;
Jeremy Hayes9d304782016-10-09 11:48:12 -06002241 if (frameCount != UINT32_MAX && curFrame == frameCount) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002242 quit = true;
2243 }
2244 }
2245 }
2246
Jeremy Hayes9d304782016-10-09 11:48:12 -06002247 void create_xcb_window() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002248 uint32_t value_mask, value_list[32];
2249
2250 xcb_window = xcb_generate_id(connection);
2251
2252 value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
2253 value_list[0] = screen->black_pixel;
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002254 value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002255
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002256 xcb_create_window(connection, XCB_COPY_FROM_PARENT, xcb_window, screen->root, 0, 0, width, height, 0,
2257 XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, value_mask, value_list);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002258
2259 /* Magic code that will send notification when window is destroyed */
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002260 xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, 1, 12, "WM_PROTOCOLS");
2261 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookie, 0);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002262
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002263 xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW");
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002264 atom_wm_delete_window = xcb_intern_atom_reply(connection, cookie2, 0);
2265
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002266 xcb_change_property(connection, XCB_PROP_MODE_REPLACE, xcb_window, (*reply).atom, 4, 32, 1, &(*atom_wm_delete_window).atom);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002267
2268 free(reply);
2269
2270 xcb_map_window(connection, xcb_window);
2271
Jeremy Hayes9d304782016-10-09 11:48:12 -06002272 // Force the x/y coordinates to 100,100 results are identical in
2273 // consecutive
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002274 // runs
2275 const uint32_t coords[] = {100, 100};
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002276 xcb_configure_window(connection, xcb_window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002277 }
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002278#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
2279
Jeremy Hayes9d304782016-10-09 11:48:12 -06002280 void run() {
2281 while (!quit) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002282 update_data_buffer();
2283 draw();
2284 curFrame++;
Jeremy Hayes9d304782016-10-09 11:48:12 -06002285 if (frameCount != UINT32_MAX && curFrame == frameCount) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002286 quit = true;
2287 }
2288 }
2289 }
2290
Jeremy Hayes9d304782016-10-09 11:48:12 -06002291 void create_window() {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002292 window = wl_compositor_create_surface(compositor);
Jeremy Hayes9d304782016-10-09 11:48:12 -06002293 if (!window) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002294 printf("Can not create wayland_surface from compositor!\n");
2295 fflush(stdout);
2296 exit(1);
2297 }
2298
2299 shell_surface = wl_shell_get_shell_surface(shell, window);
Jeremy Hayes9d304782016-10-09 11:48:12 -06002300 if (!shell_surface) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002301 printf("Can not get shell_surface from wayland_surface!\n");
2302 fflush(stdout);
2303 exit(1);
2304 }
2305
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002306 wl_shell_surface_add_listener(shell_surface, &shell_surface_listener, this);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002307 wl_shell_surface_set_toplevel(shell_surface);
2308 wl_shell_surface_set_title(shell_surface, APP_SHORT_NAME);
2309 }
Tony Barbourefd0c5a2016-12-07 14:45:12 -07002310#elif defined(VK_USE_PLATFORM_MIR_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002311#endif
2312
2313#if defined(VK_USE_PLATFORM_WIN32_KHR)
2314 HINSTANCE connection; // hInstance - Windows Instance
2315 HWND window; // hWnd - window handle
2316 POINT minsize; // minimum window size
2317 char name[APP_NAME_STR_LEN]; // Name to put on the window/icon
Tony Barbour153cb062016-12-07 13:43:36 -07002318#elif defined(VK_USE_PLATFORM_XLIB_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002319 Window xlib_window;
2320 Atom xlib_wm_delete_window;
Tony Barbour78d6b572016-11-14 14:46:33 -07002321 Display *display;
Tony Barbour153cb062016-12-07 13:43:36 -07002322#elif defined(VK_USE_PLATFORM_XCB_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002323 xcb_window_t xcb_window;
Tony Barbour78d6b572016-11-14 14:46:33 -07002324 xcb_screen_t *screen;
2325 xcb_connection_t *connection;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002326 xcb_intern_atom_reply_t *atom_wm_delete_window;
Karl Schultz23cc2182016-11-23 17:15:17 -07002327#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002328 wl_display *display;
2329 wl_registry *registry;
2330 wl_compositor *compositor;
2331 wl_surface *window;
2332 wl_shell *shell;
2333 wl_shell_surface *shell_surface;
Tony Barbourefd0c5a2016-12-07 14:45:12 -07002334#elif defined(VK_USE_PLATFORM_MIR_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002335#endif
2336
2337 vk::SurfaceKHR surface;
2338 bool prepared;
2339 bool use_staging_buffer;
2340 bool use_xlib;
2341 bool separate_present_queue;
2342
2343 vk::Instance inst;
2344 vk::PhysicalDevice gpu;
2345 vk::Device device;
2346 vk::Queue graphics_queue;
2347 vk::Queue present_queue;
2348 uint32_t graphics_queue_family_index;
2349 uint32_t present_queue_family_index;
2350 vk::Semaphore image_acquired_semaphores[FRAME_LAG];
2351 vk::Semaphore draw_complete_semaphores[FRAME_LAG];
2352 vk::Semaphore image_ownership_semaphores[FRAME_LAG];
2353 vk::PhysicalDeviceProperties gpu_props;
2354 std::unique_ptr<vk::QueueFamilyProperties[]> queue_props;
2355 vk::PhysicalDeviceMemoryProperties memory_properties;
2356
2357 uint32_t enabled_extension_count;
2358 uint32_t enabled_layer_count;
Jeremy Hayes9d304782016-10-09 11:48:12 -06002359 char const *extension_names[64];
2360 char const *enabled_layers[64];
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002361
2362 uint32_t width;
2363 uint32_t height;
2364 vk::Format format;
2365 vk::ColorSpaceKHR color_space;
2366
2367 uint32_t swapchainImageCount;
2368 vk::SwapchainKHR swapchain;
2369 std::unique_ptr<SwapchainBuffers[]> buffers;
Jeremy Hayes6ae1f8a2016-11-16 14:47:13 -07002370 vk::PresentModeKHR presentMode;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002371 vk::Fence fences[FRAME_LAG];
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002372 uint32_t frame_index;
2373
2374 vk::CommandPool cmd_pool;
2375 vk::CommandPool present_cmd_pool;
2376
Jeremy Hayes9d304782016-10-09 11:48:12 -06002377 struct {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002378 vk::Format format;
2379 vk::Image image;
2380 vk::MemoryAllocateInfo mem_alloc;
2381 vk::DeviceMemory mem;
2382 vk::ImageView view;
2383 } depth;
2384
2385 static int32_t const texture_count = 1;
2386 texture_object textures[texture_count];
Jeremy Hayes1db0cee2016-11-16 14:15:25 -07002387 texture_object staging_texture;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002388
Jeremy Hayes9d304782016-10-09 11:48:12 -06002389 struct {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002390 vk::Buffer buf;
2391 vk::MemoryAllocateInfo mem_alloc;
2392 vk::DeviceMemory mem;
2393 vk::DescriptorBufferInfo buffer_info;
2394 } uniform_data;
2395
2396 vk::CommandBuffer cmd; // Buffer for initialization commands
2397 vk::PipelineLayout pipeline_layout;
2398 vk::DescriptorSetLayout desc_layout;
2399 vk::PipelineCache pipelineCache;
2400 vk::RenderPass render_pass;
2401 vk::Pipeline pipeline;
2402
2403 mat4x4 projection_matrix;
2404 mat4x4 view_matrix;
2405 mat4x4 model_matrix;
2406
2407 float spin_angle;
2408 float spin_increment;
2409 bool pause;
2410
2411 vk::ShaderModule vert_shader_module;
2412 vk::ShaderModule frag_shader_module;
2413
2414 vk::DescriptorPool desc_pool;
2415 vk::DescriptorSet desc_set;
2416
2417 std::unique_ptr<vk::Framebuffer[]> framebuffers;
2418
2419 bool quit;
2420 uint32_t curFrame;
2421 uint32_t frameCount;
2422 bool validate;
2423 bool use_break;
2424 bool suppress_popups;
2425
2426 uint32_t current_buffer;
2427 uint32_t queue_family_count;
2428};
2429
2430#if _WIN32
2431// Include header required for parsing the command line options.
2432#include <shellapi.h>
2433
2434Demo demo;
2435
2436// MS-Windows event handling function:
Jeremy Hayes9d304782016-10-09 11:48:12 -06002437LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
2438 switch (uMsg) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002439 case WM_CLOSE:
2440 PostQuitMessage(validation_error);
2441 break;
2442 case WM_PAINT:
2443 demo.run();
2444 break;
Jeremy Hayes9d304782016-10-09 11:48:12 -06002445 case WM_GETMINMAXINFO: // set window's minimum size
2446 ((MINMAXINFO *)lParam)->ptMinTrackSize = demo.minsize;
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002447 return 0;
2448 case WM_SIZE:
2449 // Resize the application to the new window size, except when
2450 // it was minimized. Vulkan doesn't support images or swapchains
2451 // with width=0 and height=0.
Jeremy Hayes9d304782016-10-09 11:48:12 -06002452 if (wParam != SIZE_MINIMIZED) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002453 demo.width = lParam & 0xffff;
2454 demo.height = (lParam & 0xffff0000) >> 16;
2455 demo.resize();
2456 }
2457 break;
2458 default:
2459 break;
2460 }
2461
2462 return (DefWindowProc(hWnd, uMsg, wParam, lParam));
2463}
2464
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002465int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002466 // TODO: Gah.. refactor. This isn't 1989.
2467 MSG msg; // message
2468 bool done; // flag saying when app is complete
2469 int argc;
2470 char **argv;
2471
2472 // Use the CommandLine functions to get the command line arguments.
2473 // Unfortunately, Microsoft outputs
2474 // this information as wide characters for Unicode, and we simply want the
2475 // Ascii version to be compatible
2476 // with the non-Windows side. So, we have to convert the information to
2477 // Ascii character strings.
2478 LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc);
Jeremy Hayes9d304782016-10-09 11:48:12 -06002479 if (nullptr == commandLineArgs) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002480 argc = 0;
2481 }
2482
Jeremy Hayes9d304782016-10-09 11:48:12 -06002483 if (argc > 0) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002484 argv = (char **)malloc(sizeof(char *) * argc);
Jeremy Hayes9d304782016-10-09 11:48:12 -06002485 if (argv == nullptr) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002486 argc = 0;
Jeremy Hayes9d304782016-10-09 11:48:12 -06002487 } else {
2488 for (int iii = 0; iii < argc; iii++) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002489 size_t wideCharLen = wcslen(commandLineArgs[iii]);
2490 size_t numConverted = 0;
2491
2492 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1));
Jeremy Hayes9d304782016-10-09 11:48:12 -06002493 if (argv[iii] != nullptr) {
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002494 wcstombs_s(&numConverted, argv[iii], wideCharLen + 1, commandLineArgs[iii], wideCharLen + 1);
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002495 }
2496 }
2497 }
Jeremy Hayes9d304782016-10-09 11:48:12 -06002498 } else {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002499 argv = nullptr;
2500 }
2501
2502 demo.init(argc, argv);
2503
2504 // Free up the items we had to allocate for the command line arguments.
Jeremy Hayes9d304782016-10-09 11:48:12 -06002505 if (argc > 0 && argv != nullptr) {
2506 for (int iii = 0; iii < argc; iii++) {
2507 if (argv[iii] != nullptr) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002508 free(argv[iii]);
2509 }
2510 }
2511 free(argv);
2512 }
2513
2514 demo.connection = hInstance;
2515 strncpy(demo.name, "cube", APP_NAME_STR_LEN);
2516 demo.create_window();
2517 demo.init_vk_swapchain();
2518
2519 demo.prepare();
2520
2521 done = false; // initialize loop condition variable
2522
2523 // main message loop
Jeremy Hayes9d304782016-10-09 11:48:12 -06002524 while (!done) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002525 PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE);
Jeremy Hayes9d304782016-10-09 11:48:12 -06002526 if (msg.message == WM_QUIT) // check for a quit message
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002527 {
2528 done = true; // if found, quit app
Jeremy Hayes9d304782016-10-09 11:48:12 -06002529 } else {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002530 /* Translate and dispatch to event queue*/
2531 TranslateMessage(&msg);
2532 DispatchMessage(&msg);
2533 }
2534 RedrawWindow(demo.window, nullptr, nullptr, RDW_INTERNALPAINT);
2535 }
2536
2537 demo.cleanup();
2538
2539 return (int)msg.wParam;
2540}
2541
2542#elif __linux__
2543
Jeremy Hayes9d304782016-10-09 11:48:12 -06002544int main(int argc, char **argv) {
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002545 Demo demo;
2546
2547 demo.init(argc, argv);
2548
Tony Barbour153cb062016-12-07 13:43:36 -07002549#if defined(VK_USE_PLATFORM_XCB_KHR)
Jeremy Hayes9d304782016-10-09 11:48:12 -06002550 demo.create_xcb_window();
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002551#elif defined(VK_USE_PLATFORM_XLIB_KHR)
Tony Barbour78d6b572016-11-14 14:46:33 -07002552 demo.use_xlib = true;
Jeremy Hayes9d304782016-10-09 11:48:12 -06002553 demo.create_xlib_window();
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002554#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
Jeremy Hayes9d304782016-10-09 11:48:12 -06002555 demo.create_window();
Tony Barbourefd0c5a2016-12-07 14:45:12 -07002556#elif defined(VK_USE_PLATFORM_MIR_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002557#endif
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002558
2559 demo.init_vk_swapchain();
2560
2561 demo.prepare();
2562
Tony Barbour153cb062016-12-07 13:43:36 -07002563#if defined(VK_USE_PLATFORM_XCB_KHR)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002564 demo.run_xcb();
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002565#elif defined(VK_USE_PLATFORM_XLIB_KHR)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002566 demo.run_xlib();
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002567#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
Mark Lobodzinski2dbc2662017-01-26 12:16:30 -07002568 demo.run();
Tony Barbourefd0c5a2016-12-07 14:45:12 -07002569#elif defined(VK_USE_PLATFORM_MIR_KHR)
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002570#endif
Jeremy Hayesf56427a2016-09-07 15:55:11 -06002571
2572 demo.cleanup();
2573
2574 return validation_error;
2575}
2576
2577#else
2578#error "Platform not supported"
2579#endif