1/* 2* Copyright (c) 2015-2016 The Khronos Group Inc. 3* Copyright (c) 2015-2016 Valve Corporation 4* Copyright (c) 2015-2016 LunarG, Inc. 5* 6* Licensed under the Apache License, Version 2.0 (the "License"); 7* you may not use this file except in compliance with the License. 8* You may obtain a copy of the License at 9* 10* http://www.apache.org/licenses/LICENSE-2.0 11* 12* Unless required by applicable law or agreed to in writing, software 13* distributed under the License is distributed on an "AS IS" BASIS, 14* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15* See the License for the specific language governing permissions and 16* limitations under the License. 17* 18* Author: Chia-I Wu <olv@lunarg.com> 19* Author: Courtney Goeltzenleuchter <courtney@LunarG.com> 20* Author: Ian Elliott <ian@LunarG.com> 21* Author: Jon Ashburn <jon@lunarg.com> 22* Author: Gwan-gyeong Mun <elongbug@gmail.com> 23* Author: Tony Barbour <tony@LunarG.com> 24*/ 25 26#define _GNU_SOURCE 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30#include <stdbool.h> 31#include <assert.h> 32#include <signal.h> 33#if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR) 34#include <X11/Xutil.h> 35#endif 36 37#ifdef _WIN32 38#pragma comment(linker, "/subsystem:windows") 39#define APP_NAME_STR_LEN 80 40#endif // _WIN32 41 42#ifdef ANDROID 43#include "vulkan_wrapper.h" 44#else 45#include <vulkan/vulkan.h> 46#endif 47 48#include <vulkan/vk_sdk_platform.h> 49#include "linmath.h" 50 51#define DEMO_TEXTURE_COUNT 1 52#define APP_SHORT_NAME "cube" 53#define APP_LONG_NAME "The Vulkan Cube Demo Program" 54 55// Allow a maximum of two outstanding presentation operations. 56#define FRAME_LAG 2 57 58#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 59 60#if defined(NDEBUG) && defined(__GNUC__) 61#define U_ASSERT_ONLY __attribute__((unused)) 62#else 63#define U_ASSERT_ONLY 64#endif 65 66#if defined(__GNUC__) 67#define UNUSED __attribute__((unused)) 68#else 69#define UNUSED 70#endif 71 72#ifdef _WIN32 73bool in_callback = false; 74#define ERR_EXIT(err_msg, err_class) \ 75 do { \ 76 if (!demo->suppress_popups) \ 77 MessageBox(NULL, err_msg, err_class, MB_OK); \ 78 exit(1); \ 79 } while (0) 80 81#elif defined __ANDROID__ 82#include <android/log.h> 83#define ERR_EXIT(err_msg, err_class) \ 84 do { \ 85 ((void)__android_log_print(ANDROID_LOG_INFO, "Cube", err_msg)); \ 86 exit(1); \ 87 } while (0) 88#else 89#define ERR_EXIT(err_msg, err_class) \ 90 do { \ 91 printf(err_msg); \ 92 fflush(stdout); \ 93 exit(1); \ 94 } while (0) 95#endif 96 97#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \ 98 { \ 99 demo->fp##entrypoint = \ 100 (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \ 101 if (demo->fp##entrypoint == NULL) { \ 102 ERR_EXIT("vkGetInstanceProcAddr failed to find vk" #entrypoint, \ 103 "vkGetInstanceProcAddr Failure"); \ 104 } \ 105 } 106 107static PFN_vkGetDeviceProcAddr g_gdpa = NULL; 108 109#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \ 110 { \ 111 if (!g_gdpa) \ 112 g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr( \ 113 demo->inst, "vkGetDeviceProcAddr"); \ 114 demo->fp##entrypoint = \ 115 (PFN_vk##entrypoint)g_gdpa(dev, "vk" #entrypoint); \ 116 if (demo->fp##entrypoint == NULL) { \ 117 ERR_EXIT("vkGetDeviceProcAddr failed to find vk" #entrypoint, \ 118 "vkGetDeviceProcAddr Failure"); \ 119 } \ 120 } 121 122/* 123 * structure to track all objects related to a texture. 124 */ 125struct texture_object { 126 VkSampler sampler; 127 128 VkImage image; 129 VkImageLayout imageLayout; 130 131 VkMemoryAllocateInfo mem_alloc; 132 VkDeviceMemory mem; 133 VkImageView view; 134 int32_t tex_width, tex_height; 135}; 136 137static char *tex_files[] = {"lunarg.ppm"}; 138 139static int validation_error = 0; 140 141struct vkcube_vs_uniform { 142 // Must start with MVP 143 float mvp[4][4]; 144 float position[12 * 3][4]; 145 float color[12 * 3][4]; 146}; 147 148struct vktexcube_vs_uniform { 149 // Must start with MVP 150 float mvp[4][4]; 151 float position[12 * 3][4]; 152 float attr[12 * 3][4]; 153}; 154 155//-------------------------------------------------------------------------------------- 156// Mesh and VertexFormat Data 157//-------------------------------------------------------------------------------------- 158// clang-format off 159static const float g_vertex_buffer_data[] = { 160 -1.0f,-1.0f,-1.0f, // -X side 161 -1.0f,-1.0f, 1.0f, 162 -1.0f, 1.0f, 1.0f, 163 -1.0f, 1.0f, 1.0f, 164 -1.0f, 1.0f,-1.0f, 165 -1.0f,-1.0f,-1.0f, 166 167 -1.0f,-1.0f,-1.0f, // -Z side 168 1.0f, 1.0f,-1.0f, 169 1.0f,-1.0f,-1.0f, 170 -1.0f,-1.0f,-1.0f, 171 -1.0f, 1.0f,-1.0f, 172 1.0f, 1.0f,-1.0f, 173 174 -1.0f,-1.0f,-1.0f, // -Y side 175 1.0f,-1.0f,-1.0f, 176 1.0f,-1.0f, 1.0f, 177 -1.0f,-1.0f,-1.0f, 178 1.0f,-1.0f, 1.0f, 179 -1.0f,-1.0f, 1.0f, 180 181 -1.0f, 1.0f,-1.0f, // +Y side 182 -1.0f, 1.0f, 1.0f, 183 1.0f, 1.0f, 1.0f, 184 -1.0f, 1.0f,-1.0f, 185 1.0f, 1.0f, 1.0f, 186 1.0f, 1.0f,-1.0f, 187 188 1.0f, 1.0f,-1.0f, // +X side 189 1.0f, 1.0f, 1.0f, 190 1.0f,-1.0f, 1.0f, 191 1.0f,-1.0f, 1.0f, 192 1.0f,-1.0f,-1.0f, 193 1.0f, 1.0f,-1.0f, 194 195 -1.0f, 1.0f, 1.0f, // +Z side 196 -1.0f,-1.0f, 1.0f, 197 1.0f, 1.0f, 1.0f, 198 -1.0f,-1.0f, 1.0f, 199 1.0f,-1.0f, 1.0f, 200 1.0f, 1.0f, 1.0f, 201}; 202 203static const float g_uv_buffer_data[] = { 204 0.0f, 1.0f, // -X side 205 1.0f, 1.0f, 206 1.0f, 0.0f, 207 1.0f, 0.0f, 208 0.0f, 0.0f, 209 0.0f, 1.0f, 210 211 1.0f, 1.0f, // -Z side 212 0.0f, 0.0f, 213 0.0f, 1.0f, 214 1.0f, 1.0f, 215 1.0f, 0.0f, 216 0.0f, 0.0f, 217 218 1.0f, 0.0f, // -Y side 219 1.0f, 1.0f, 220 0.0f, 1.0f, 221 1.0f, 0.0f, 222 0.0f, 1.0f, 223 0.0f, 0.0f, 224 225 1.0f, 0.0f, // +Y side 226 0.0f, 0.0f, 227 0.0f, 1.0f, 228 1.0f, 0.0f, 229 0.0f, 1.0f, 230 1.0f, 1.0f, 231 232 1.0f, 0.0f, // +X side 233 0.0f, 0.0f, 234 0.0f, 1.0f, 235 0.0f, 1.0f, 236 1.0f, 1.0f, 237 1.0f, 0.0f, 238 239 0.0f, 0.0f, // +Z side 240 0.0f, 1.0f, 241 1.0f, 0.0f, 242 0.0f, 1.0f, 243 1.0f, 1.0f, 244 1.0f, 0.0f, 245}; 246// clang-format on 247 248void dumpMatrix(const char *note, mat4x4 MVP) { 249 int i; 250 251 printf("%s: \n", note); 252 for (i = 0; i < 4; i++) { 253 printf("%f, %f, %f, %f\n", MVP[i][0], MVP[i][1], MVP[i][2], MVP[i][3]); 254 } 255 printf("\n"); 256 fflush(stdout); 257} 258 259void dumpVec4(const char *note, vec4 vector) { 260 printf("%s: \n", note); 261 printf("%f, %f, %f, %f\n", vector[0], vector[1], vector[2], vector[3]); 262 printf("\n"); 263 fflush(stdout); 264} 265 266VKAPI_ATTR VkBool32 VKAPI_CALL 267BreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, 268 uint64_t srcObject, size_t location, int32_t msgCode, 269 const char *pLayerPrefix, const char *pMsg, 270 void *pUserData) { 271#ifndef WIN32 272 raise(SIGTRAP); 273#else 274 DebugBreak(); 275#endif 276 277 return false; 278} 279 280typedef struct { 281 VkImage image; 282 VkCommandBuffer cmd; 283 VkCommandBuffer graphics_to_present_cmd; 284 VkImageView view; 285} SwapchainBuffers; 286 287struct demo { 288#if defined(VK_USE_PLATFORM_WIN32_KHR) 289#define APP_NAME_STR_LEN 80 290 HINSTANCE connection; // hInstance - Windows Instance 291 char name[APP_NAME_STR_LEN]; // Name to put on the window/icon 292 HWND window; // hWnd - window handle 293 POINT minsize; // minimum window size 294#elif defined(VK_USE_PLATFORM_XLIB_KHR) | defined(VK_USE_PLATFORM_XCB_KHR) 295 Display* display; 296 Window xlib_window; 297 Atom xlib_wm_delete_window; 298 299 xcb_connection_t *connection; 300 xcb_screen_t *screen; 301 xcb_window_t xcb_window; 302 xcb_intern_atom_reply_t *atom_wm_delete_window; 303#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) 304 struct wl_display *display; 305 struct wl_registry *registry; 306 struct wl_compositor *compositor; 307 struct wl_surface *window; 308 struct wl_shell *shell; 309 struct wl_shell_surface *shell_surface; 310#elif defined(VK_USE_PLATFORM_ANDROID_KHR) 311 ANativeWindow* window; 312#endif 313 VkSurfaceKHR surface; 314 bool prepared; 315 bool use_staging_buffer; 316 bool use_xlib; 317 bool separate_present_queue; 318 319 VkInstance inst; 320 VkPhysicalDevice gpu; 321 VkDevice device; 322 VkQueue graphics_queue; 323 VkQueue present_queue; 324 uint32_t graphics_queue_family_index; 325 uint32_t present_queue_family_index; 326 VkSemaphore image_acquired_semaphores[FRAME_LAG]; 327 VkSemaphore draw_complete_semaphores[FRAME_LAG]; 328 VkSemaphore image_ownership_semaphores[FRAME_LAG]; 329 VkPhysicalDeviceProperties gpu_props; 330 VkQueueFamilyProperties *queue_props; 331 VkPhysicalDeviceMemoryProperties memory_properties; 332 333 uint32_t enabled_extension_count; 334 uint32_t enabled_layer_count; 335 char *extension_names[64]; 336 char *enabled_layers[64]; 337 338 int width, height; 339 VkFormat format; 340 VkColorSpaceKHR color_space; 341 342 PFN_vkGetPhysicalDeviceSurfaceSupportKHR 343 fpGetPhysicalDeviceSurfaceSupportKHR; 344 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR 345 fpGetPhysicalDeviceSurfaceCapabilitiesKHR; 346 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR 347 fpGetPhysicalDeviceSurfaceFormatsKHR; 348 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR 349 fpGetPhysicalDeviceSurfacePresentModesKHR; 350 PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR; 351 PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR; 352 PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR; 353 PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR; 354 PFN_vkQueuePresentKHR fpQueuePresentKHR; 355 uint32_t swapchainImageCount; 356 VkSwapchainKHR swapchain; 357 SwapchainBuffers *buffers; 358 VkFence fences[FRAME_LAG]; 359 int frame_index; 360 361 VkCommandPool cmd_pool; 362 VkCommandPool present_cmd_pool; 363 364 struct { 365 VkFormat format; 366 367 VkImage image; 368 VkMemoryAllocateInfo mem_alloc; 369 VkDeviceMemory mem; 370 VkImageView view; 371 } depth; 372 373 struct texture_object textures[DEMO_TEXTURE_COUNT]; 374 375 struct { 376 VkBuffer buf; 377 VkMemoryAllocateInfo mem_alloc; 378 VkDeviceMemory mem; 379 VkDescriptorBufferInfo buffer_info; 380 } uniform_data; 381 382 VkCommandBuffer cmd; // Buffer for initialization commands 383 VkPipelineLayout pipeline_layout; 384 VkDescriptorSetLayout desc_layout; 385 VkPipelineCache pipelineCache; 386 VkRenderPass render_pass; 387 VkPipeline pipeline; 388 389 mat4x4 projection_matrix; 390 mat4x4 view_matrix; 391 mat4x4 model_matrix; 392 393 float spin_angle; 394 float spin_increment; 395 bool pause; 396 397 VkShaderModule vert_shader_module; 398 VkShaderModule frag_shader_module; 399 400 VkDescriptorPool desc_pool; 401 VkDescriptorSet desc_set; 402 403 VkFramebuffer *framebuffers; 404 405 bool quit; 406 int32_t curFrame; 407 int32_t frameCount; 408 bool validate; 409 bool use_break; 410 bool suppress_popups; 411 PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback; 412 PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback; 413 VkDebugReportCallbackEXT msg_callback; 414 PFN_vkDebugReportMessageEXT DebugReportMessage; 415 416 uint32_t current_buffer; 417 uint32_t queue_family_count; 418}; 419 420VKAPI_ATTR VkBool32 VKAPI_CALL 421dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, 422 uint64_t srcObject, size_t location, int32_t msgCode, 423 const char *pLayerPrefix, const char *pMsg, void *pUserData) { 424 425 // clang-format off 426 char *message = (char *)malloc(strlen(pMsg) + 100); 427 428 assert(message); 429 430 // We know we're submitting queues without fences, ignore this 431 if (strstr(pMsg, "vkQueueSubmit parameter, VkFence fence, is null pointer")) 432 return false; 433 434 if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { 435 sprintf(message, "INFORMATION: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 436 validation_error = 1; 437 } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { 438 sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 439 validation_error = 1; 440 } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { 441 sprintf(message, "PERFORMANCE WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 442 validation_error = 1; 443 } else if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { 444 sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 445 validation_error = 1; 446 } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { 447 sprintf(message, "DEBUG: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 448 validation_error = 1; 449 } else { 450 sprintf(message, "INFORMATION: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 451 validation_error = 1; 452 } 453 454#ifdef _WIN32 455 456 in_callback = true; 457 struct demo *demo = (struct demo*) pUserData; 458 if (!demo->suppress_popups) 459 MessageBox(NULL, message, "Alert", MB_OK); 460 in_callback = false; 461 462#elif defined(ANDROID) 463 464 if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { 465 __android_log_print(ANDROID_LOG_INFO, APP_SHORT_NAME, "%s", message); 466 } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { 467 __android_log_print(ANDROID_LOG_WARN, APP_SHORT_NAME, "%s", message); 468 } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { 469 __android_log_print(ANDROID_LOG_WARN, APP_SHORT_NAME, "%s", message); 470 } else if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { 471 __android_log_print(ANDROID_LOG_ERROR, APP_SHORT_NAME, "%s", message); 472 } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { 473 __android_log_print(ANDROID_LOG_DEBUG, APP_SHORT_NAME, "%s", message); 474 } else { 475 __android_log_print(ANDROID_LOG_INFO, APP_SHORT_NAME, "%s", message); 476 } 477 478#else 479 480 printf("%s\n", message); 481 fflush(stdout); 482 483#endif 484 485 free(message); 486 487 //clang-format on 488 489 /* 490 * false indicates that layer should not bail-out of an 491 * API call that had validation failures. This may mean that the 492 * app dies inside the driver due to invalid parameter(s). 493 * That's what would happen without validation layers, so we'll 494 * keep that behavior here. 495 */ 496 return false; 497} 498 499// Forward declaration: 500static void demo_resize(struct demo *demo); 501 502static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits, 503 VkFlags requirements_mask, 504 uint32_t *typeIndex) { 505 // Search memtypes to find first index with those properties 506 for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) { 507 if ((typeBits & 1) == 1) { 508 // Type is available, does it match user properties? 509 if ((demo->memory_properties.memoryTypes[i].propertyFlags & 510 requirements_mask) == requirements_mask) { 511 *typeIndex = i; 512 return true; 513 } 514 } 515 typeBits >>= 1; 516 } 517 // No memory types matched, return failure 518 return false; 519} 520 521static void demo_flush_init_cmd(struct demo *demo) { 522 VkResult U_ASSERT_ONLY err; 523 524 // This function could get called twice if the texture uses a staging buffer 525 // In that case the second call should be ignored 526 if (demo->cmd == VK_NULL_HANDLE) 527 return; 528 529 err = vkEndCommandBuffer(demo->cmd); 530 assert(!err); 531 532 VkFence fence; 533 VkFenceCreateInfo fence_ci = {.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 534 .pNext = NULL, 535 .flags = 0}; 536 vkCreateFence(demo->device, &fence_ci, NULL, &fence); 537 const VkCommandBuffer cmd_bufs[] = {demo->cmd}; 538 VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 539 .pNext = NULL, 540 .waitSemaphoreCount = 0, 541 .pWaitSemaphores = NULL, 542 .pWaitDstStageMask = NULL, 543 .commandBufferCount = 1, 544 .pCommandBuffers = cmd_bufs, 545 .signalSemaphoreCount = 0, 546 .pSignalSemaphores = NULL}; 547 548 err = vkQueueSubmit(demo->graphics_queue, 1, &submit_info, fence); 549 assert(!err); 550 551 err = vkWaitForFences(demo->device, 1, &fence, VK_TRUE, UINT64_MAX); 552 assert(!err); 553 554 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, cmd_bufs); 555 vkDestroyFence(demo->device, fence, NULL); 556 demo->cmd = VK_NULL_HANDLE; 557} 558 559static void demo_set_image_layout(struct demo *demo, VkImage image, 560 VkImageAspectFlags aspectMask, 561 VkImageLayout old_image_layout, 562 VkImageLayout new_image_layout, 563 VkAccessFlagBits srcAccessMask, 564 VkPipelineStageFlags src_stages, 565 VkPipelineStageFlags dest_stages) { 566 VkResult U_ASSERT_ONLY err; 567 568 if (demo->cmd == VK_NULL_HANDLE) { 569 const VkCommandBufferAllocateInfo cmd = { 570 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 571 .pNext = NULL, 572 .commandPool = demo->cmd_pool, 573 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 574 .commandBufferCount = 1, 575 }; 576 577 err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->cmd); 578 assert(!err); 579 VkCommandBufferBeginInfo cmd_buf_info = { 580 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 581 .pNext = NULL, 582 .flags = 0, 583 .pInheritanceInfo = NULL, 584 }; 585 err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info); 586 assert(!err); 587 } 588 589 VkImageMemoryBarrier image_memory_barrier = { 590 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 591 .pNext = NULL, 592 .srcAccessMask = srcAccessMask, 593 .dstAccessMask = 0, 594 .oldLayout = old_image_layout, 595 .newLayout = new_image_layout, 596 .image = image, 597 .subresourceRange = {aspectMask, 0, 1, 0, 1}}; 598 599 switch (new_image_layout) { 600 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: 601 /* Make sure anything that was copying from this image has completed */ 602 image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 603 break; 604 605 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: 606 image_memory_barrier.dstAccessMask = 607 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 608 break; 609 610 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: 611 image_memory_barrier.dstAccessMask = 612 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; 613 break; 614 615 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: 616 image_memory_barrier.dstAccessMask = 617 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; 618 break; 619 620 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: 621 image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; 622 break; 623 624 case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: 625 image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; 626 break; 627 628 default: 629 image_memory_barrier.dstAccessMask = 0; 630 break; 631 } 632 633 634 VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier; 635 636 vkCmdPipelineBarrier(demo->cmd, src_stages, dest_stages, 0, 0, NULL, 0, 637 NULL, 1, pmemory_barrier); 638} 639 640static void demo_draw_build_cmd(struct demo *demo, VkCommandBuffer cmd_buf) { 641 const VkCommandBufferBeginInfo cmd_buf_info = { 642 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 643 .pNext = NULL, 644 .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, 645 .pInheritanceInfo = NULL, 646 }; 647 const VkClearValue clear_values[2] = { 648 [0] = {.color.float32 = {0.2f, 0.2f, 0.2f, 0.2f}}, 649 [1] = {.depthStencil = {1.0f, 0}}, 650 }; 651 const VkRenderPassBeginInfo rp_begin = { 652 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 653 .pNext = NULL, 654 .renderPass = demo->render_pass, 655 .framebuffer = demo->framebuffers[demo->current_buffer], 656 .renderArea.offset.x = 0, 657 .renderArea.offset.y = 0, 658 .renderArea.extent.width = demo->width, 659 .renderArea.extent.height = demo->height, 660 .clearValueCount = 2, 661 .pClearValues = clear_values, 662 }; 663 VkResult U_ASSERT_ONLY err; 664 665 err = vkBeginCommandBuffer(cmd_buf, &cmd_buf_info); 666 assert(!err); 667 vkCmdBeginRenderPass(cmd_buf, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); 668 vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline); 669 vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, 670 demo->pipeline_layout, 0, 1, &demo->desc_set, 0, 671 NULL); 672 VkViewport viewport; 673 memset(&viewport, 0, sizeof(viewport)); 674 viewport.height = (float)demo->height; 675 viewport.width = (float)demo->width; 676 viewport.minDepth = (float)0.0f; 677 viewport.maxDepth = (float)1.0f; 678 vkCmdSetViewport(cmd_buf, 0, 1, &viewport); 679 680 VkRect2D scissor; 681 memset(&scissor, 0, sizeof(scissor)); 682 scissor.extent.width = demo->width; 683 scissor.extent.height = demo->height; 684 scissor.offset.x = 0; 685 scissor.offset.y = 0; 686 vkCmdSetScissor(cmd_buf, 0, 1, &scissor); 687 vkCmdDraw(cmd_buf, 12 * 3, 1, 0, 0); 688 // Note that ending the renderpass changes the image's layout from 689 // COLOR_ATTACHMENT_OPTIMAL to PRESENT_SRC_KHR 690 vkCmdEndRenderPass(cmd_buf); 691 692 if (demo->separate_present_queue) { 693 // We have to transfer ownership from the graphics queue family to the 694 // present queue family to be able to present. Note that we don't have 695 // to transfer from present queue family back to graphics queue family at 696 // the start of the next frame because we don't care about the image's 697 // contents at that point. 698 VkImageMemoryBarrier image_ownership_barrier = { 699 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 700 .pNext = NULL, 701 .srcAccessMask = 0, 702 .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 703 .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 704 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 705 .srcQueueFamilyIndex = demo->graphics_queue_family_index, 706 .dstQueueFamilyIndex = demo->present_queue_family_index, 707 .image = demo->buffers[demo->current_buffer].image, 708 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; 709 710 vkCmdPipelineBarrier(cmd_buf, 711 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 712 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 713 0, NULL, 0, NULL, 1, &image_ownership_barrier); 714 } 715 err = vkEndCommandBuffer(cmd_buf); 716 assert(!err); 717} 718 719void demo_build_image_ownership_cmd(struct demo *demo, int i) { 720 VkResult U_ASSERT_ONLY err; 721 722 const VkCommandBufferBeginInfo cmd_buf_info = { 723 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 724 .pNext = NULL, 725 .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, 726 .pInheritanceInfo = NULL, 727 }; 728 err = vkBeginCommandBuffer(demo->buffers[i].graphics_to_present_cmd, 729 &cmd_buf_info); 730 assert(!err); 731 732 VkImageMemoryBarrier image_ownership_barrier = { 733 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 734 .pNext = NULL, 735 .srcAccessMask = 0, 736 .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 737 .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 738 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 739 .srcQueueFamilyIndex = demo->graphics_queue_family_index, 740 .dstQueueFamilyIndex = demo->present_queue_family_index, 741 .image = demo->buffers[i].image, 742 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; 743 744 vkCmdPipelineBarrier(demo->buffers[i].graphics_to_present_cmd, 745 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 746 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, 747 NULL, 0, NULL, 1, &image_ownership_barrier); 748 err = vkEndCommandBuffer(demo->buffers[i].graphics_to_present_cmd); 749 assert(!err); 750} 751 752void demo_update_data_buffer(struct demo *demo) { 753 mat4x4 MVP, Model, VP; 754 int matrixSize = sizeof(MVP); 755 uint8_t *pData; 756 VkResult U_ASSERT_ONLY err; 757 758 mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix); 759 760 // Rotate 22.5 degrees around the Y axis 761 mat4x4_dup(Model, demo->model_matrix); 762 mat4x4_rotate(demo->model_matrix, Model, 0.0f, 1.0f, 0.0f, 763 (float)degreesToRadians(demo->spin_angle)); 764 mat4x4_mul(MVP, VP, demo->model_matrix); 765 766 err = vkMapMemory(demo->device, demo->uniform_data.mem, 0, 767 demo->uniform_data.mem_alloc.allocationSize, 0, 768 (void **)&pData); 769 assert(!err); 770 771 memcpy(pData, (const void *)&MVP[0][0], matrixSize); 772 773 vkUnmapMemory(demo->device, demo->uniform_data.mem); 774} 775 776static void demo_draw(struct demo *demo) { 777 VkResult U_ASSERT_ONLY err; 778 779 // Ensure no more than FRAME_LAG presentations are outstanding 780 vkWaitForFences(demo->device, 1, &demo->fences[demo->frame_index], VK_TRUE, UINT64_MAX); 781 vkResetFences(demo->device, 1, &demo->fences[demo->frame_index]); 782 783 // Get the index of the next available swapchain image: 784 err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX, 785 demo->image_acquired_semaphores[demo->frame_index], demo->fences[demo->frame_index], 786 &demo->current_buffer); 787 788 if (err == VK_ERROR_OUT_OF_DATE_KHR) { 789 // demo->swapchain is out of date (e.g. the window was resized) and 790 // must be recreated: 791 demo->frame_index += 1; 792 demo->frame_index %= FRAME_LAG; 793 794 demo_resize(demo); 795 demo_draw(demo); 796 return; 797 } else if (err == VK_SUBOPTIMAL_KHR) { 798 // demo->swapchain is not as optimal as it could be, but the platform's 799 // presentation engine will still present the image correctly. 800 } else { 801 assert(!err); 802 } 803 // Wait for the image acquired semaphore to be signaled to ensure 804 // that the image won't be rendered to until the presentation 805 // engine has fully released ownership to the application, and it is 806 // okay to render to the image. 807 VkFence nullFence = VK_NULL_HANDLE; 808 VkPipelineStageFlags pipe_stage_flags; 809 VkSubmitInfo submit_info; 810 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 811 submit_info.pNext = NULL; 812 submit_info.pWaitDstStageMask = &pipe_stage_flags; 813 pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 814 submit_info.waitSemaphoreCount = 1; 815 submit_info.pWaitSemaphores = &demo->image_acquired_semaphores[demo->frame_index]; 816 submit_info.commandBufferCount = 1; 817 submit_info.pCommandBuffers = &demo->buffers[demo->current_buffer].cmd; 818 submit_info.signalSemaphoreCount = 1; 819 submit_info.pSignalSemaphores = &demo->draw_complete_semaphores[demo->frame_index]; 820 err = vkQueueSubmit(demo->graphics_queue, 1, &submit_info, nullFence); 821 assert(!err); 822 823 if (demo->separate_present_queue) { 824 // If we are using separate queues, change image ownership to the 825 // present queue before presenting, waiting for the draw complete 826 // semaphore and signalling the ownership released semaphore when finished 827 pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 828 submit_info.waitSemaphoreCount = 1; 829 submit_info.pWaitSemaphores = &demo->draw_complete_semaphores[demo->frame_index]; 830 submit_info.commandBufferCount = 1; 831 submit_info.pCommandBuffers = 832 &demo->buffers[demo->current_buffer].graphics_to_present_cmd; 833 submit_info.signalSemaphoreCount = 1; 834 submit_info.pSignalSemaphores = &demo->image_ownership_semaphores[demo->frame_index]; 835 err = vkQueueSubmit(demo->present_queue, 1, &submit_info, nullFence); 836 assert(!err); 837 } 838 839 // If we are using separate queues we have to wait for image ownership, 840 // otherwise wait for draw complete 841 VkPresentInfoKHR present = { 842 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 843 .pNext = NULL, 844 .waitSemaphoreCount = 1, 845 .pWaitSemaphores = (demo->separate_present_queue) 846 ? &demo->image_ownership_semaphores[demo->frame_index] 847 : &demo->draw_complete_semaphores[demo->frame_index], 848 .swapchainCount = 1, 849 .pSwapchains = &demo->swapchain, 850 .pImageIndices = &demo->current_buffer, 851 }; 852 853 err = demo->fpQueuePresentKHR(demo->present_queue, &present); 854 demo->frame_index += 1; 855 demo->frame_index %= FRAME_LAG; 856 857 if (err == VK_ERROR_OUT_OF_DATE_KHR) { 858 // demo->swapchain is out of date (e.g. the window was resized) and 859 // must be recreated: 860 demo_resize(demo); 861 } else if (err == VK_SUBOPTIMAL_KHR) { 862 // demo->swapchain is not as optimal as it could be, but the platform's 863 // presentation engine will still present the image correctly. 864 } else { 865 assert(!err); 866 } 867} 868 869static void demo_prepare_buffers(struct demo *demo) { 870 VkResult U_ASSERT_ONLY err; 871 VkSwapchainKHR oldSwapchain = demo->swapchain; 872 873 // Check the surface capabilities and formats 874 VkSurfaceCapabilitiesKHR surfCapabilities; 875 err = demo->fpGetPhysicalDeviceSurfaceCapabilitiesKHR( 876 demo->gpu, demo->surface, &surfCapabilities); 877 assert(!err); 878 879 uint32_t presentModeCount; 880 err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR( 881 demo->gpu, demo->surface, &presentModeCount, NULL); 882 assert(!err); 883 VkPresentModeKHR *presentModes = 884 (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR)); 885 assert(presentModes); 886 err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR( 887 demo->gpu, demo->surface, &presentModeCount, presentModes); 888 assert(!err); 889 890 VkExtent2D swapchainExtent; 891 // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF. 892 if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) { 893 // If the surface size is undefined, the size is set to the size 894 // of the images requested, which must fit within the minimum and 895 // maximum values. 896 swapchainExtent.width = demo->width; 897 swapchainExtent.height = demo->height; 898 899 if (swapchainExtent.width < surfCapabilities.minImageExtent.width) { 900 swapchainExtent.width = surfCapabilities.minImageExtent.width; 901 } else if (swapchainExtent.width > surfCapabilities.maxImageExtent.width) { 902 swapchainExtent.width = surfCapabilities.maxImageExtent.width; 903 } 904 905 if (swapchainExtent.height < surfCapabilities.minImageExtent.height) { 906 swapchainExtent.height = surfCapabilities.minImageExtent.height; 907 } else if (swapchainExtent.height > surfCapabilities.maxImageExtent.height) { 908 swapchainExtent.height = surfCapabilities.maxImageExtent.height; 909 } 910 } else { 911 // If the surface size is defined, the swap chain size must match 912 swapchainExtent = surfCapabilities.currentExtent; 913 demo->width = surfCapabilities.currentExtent.width; 914 demo->height = surfCapabilities.currentExtent.height; 915 } 916 917 // The FIFO present mode is guaranteed by the spec to be supported 918 // and to have no tearing. It's a great default present mode to use. 919 VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; 920 // There are times when you may wish to use another present mode. The 921 // following code shows how to select them, and the comments provide some 922 // reasons you may wish to use them. 923 // 924 // It should be noted that Vulkan 1.0 doesn't provide a method for 925 // synchronizing rendering with the presentation engine's display. There 926 // is a method provided for throttling rendering with the display, but 927 // there are some presentation engines for which this method will not work. 928 // If an application doesn't throttle its rendering, and if it renders much 929 // faster than the refresh rate of the display, this can waste power on 930 // mobile devices. That is because power is being spent rendering images 931 // that may never be seen. 932//#define DESIRE_VK_PRESENT_MODE_IMMEDIATE_KHR 933//#define DESIRE_VK_PRESENT_MODE_MAILBOX_KHR 934//#define DESIRE_VK_PRESENT_MODE_FIFO_RELAXED_KHR 935#if defined(DESIRE_VK_PRESENT_MODE_IMMEDIATE_KHR) 936 // VK_PRESENT_MODE_IMMEDIATE_KHR is for applications that don't care about 937 // tearing, or have some way of synchronizing their rendering with the 938 // display. 939 for (size_t i = 0; i < presentModeCount; ++i) { 940 if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { 941 swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; 942 break; 943 } 944 } 945#elif defined(DESIRE_VK_PRESENT_MODE_MAILBOX_KHR) 946 // VK_PRESENT_MODE_MAILBOX_KHR may be useful for applications that 947 // generally render a new presentable image every refresh cycle, but are 948 // occasionally early. In this case, the application wants the new image 949 // to be displayed instead of the previously-queued-for-presentation image 950 // that has not yet been displayed. 951 for (size_t i = 0; i < presentModeCount; ++i) { 952 if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { 953 swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; 954 break; 955 } 956 } 957#elif defined(DESIRE_VK_PRESENT_MODE_FIFO_RELAXED_KHR) 958 // VK_PRESENT_MODE_FIFO_RELAXED_KHR is for applications that generally 959 // render a new presentable image every refresh cycle, but are occasionally 960 // late. In this case (perhaps because of stuttering/latency concerns), 961 // the application wants the late image to be immediately displayed, even 962 // though that may mean some tearing. 963 for (size_t i = 0; i < presentModeCount; ++i) { 964 if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { 965 swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; 966 break; 967 } 968 } 969#endif 970 971 // Determine the number of VkImage's to use in the swap chain. 972 // Application desires to only acquire 1 image at a time (which is 973 // "surfCapabilities.minImageCount"). 974 uint32_t desiredNumOfSwapchainImages = surfCapabilities.minImageCount; 975 // If maxImageCount is 0, we can ask for as many images as we want; 976 // otherwise we're limited to maxImageCount 977 if ((surfCapabilities.maxImageCount > 0) && 978 (desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) { 979 // Application must settle for fewer images than desired: 980 desiredNumOfSwapchainImages = surfCapabilities.maxImageCount; 981 } 982 983 VkSurfaceTransformFlagsKHR preTransform; 984 if (surfCapabilities.supportedTransforms & 985 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { 986 preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 987 } else { 988 preTransform = surfCapabilities.currentTransform; 989 } 990 991 VkSwapchainCreateInfoKHR swapchain_ci = { 992 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 993 .pNext = NULL, 994 .surface = demo->surface, 995 .minImageCount = desiredNumOfSwapchainImages, 996 .imageFormat = demo->format, 997 .imageColorSpace = demo->color_space, 998 .imageExtent = 999 { 1000 .width = swapchainExtent.width, .height = swapchainExtent.height, 1001 }, 1002 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 1003 .preTransform = preTransform, 1004 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, 1005 .imageArrayLayers = 1, 1006 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, 1007 .queueFamilyIndexCount = 0, 1008 .pQueueFamilyIndices = NULL, 1009 .presentMode = swapchainPresentMode, 1010 .oldSwapchain = oldSwapchain, 1011 .clipped = true, 1012 }; 1013 uint32_t i; 1014 err = demo->fpCreateSwapchainKHR(demo->device, &swapchain_ci, NULL, 1015 &demo->swapchain); 1016 assert(!err); 1017 1018 // If we just re-created an existing swapchain, we should destroy the old 1019 // swapchain at this point. 1020 // Note: destroying the swapchain also cleans up all its associated 1021 // presentable images once the platform is done with them. 1022 if (oldSwapchain != VK_NULL_HANDLE) { 1023 demo->fpDestroySwapchainKHR(demo->device, oldSwapchain, NULL); 1024 } 1025 1026 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain, 1027 &demo->swapchainImageCount, NULL); 1028 assert(!err); 1029 1030 VkImage *swapchainImages = 1031 (VkImage *)malloc(demo->swapchainImageCount * sizeof(VkImage)); 1032 assert(swapchainImages); 1033 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain, 1034 &demo->swapchainImageCount, 1035 swapchainImages); 1036 assert(!err); 1037 1038 demo->buffers = (SwapchainBuffers *)malloc(sizeof(SwapchainBuffers) * 1039 demo->swapchainImageCount); 1040 assert(demo->buffers); 1041 1042 for (i = 0; i < demo->swapchainImageCount; i++) { 1043 VkImageViewCreateInfo color_image_view = { 1044 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 1045 .pNext = NULL, 1046 .format = demo->format, 1047 .components = 1048 { 1049 .r = VK_COMPONENT_SWIZZLE_R, 1050 .g = VK_COMPONENT_SWIZZLE_G, 1051 .b = VK_COMPONENT_SWIZZLE_B, 1052 .a = VK_COMPONENT_SWIZZLE_A, 1053 }, 1054 .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 1055 .baseMipLevel = 0, 1056 .levelCount = 1, 1057 .baseArrayLayer = 0, 1058 .layerCount = 1}, 1059 .viewType = VK_IMAGE_VIEW_TYPE_2D, 1060 .flags = 0, 1061 }; 1062 1063 demo->buffers[i].image = swapchainImages[i]; 1064 1065 color_image_view.image = demo->buffers[i].image; 1066 1067 err = vkCreateImageView(demo->device, &color_image_view, NULL, 1068 &demo->buffers[i].view); 1069 assert(!err); 1070 1071 } 1072 1073 if (NULL != presentModes) { 1074 free(presentModes); 1075 } 1076} 1077 1078static void demo_prepare_depth(struct demo *demo) { 1079 const VkFormat depth_format = VK_FORMAT_D16_UNORM; 1080 const VkImageCreateInfo image = { 1081 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 1082 .pNext = NULL, 1083 .imageType = VK_IMAGE_TYPE_2D, 1084 .format = depth_format, 1085 .extent = {demo->width, demo->height, 1}, 1086 .mipLevels = 1, 1087 .arrayLayers = 1, 1088 .samples = VK_SAMPLE_COUNT_1_BIT, 1089 .tiling = VK_IMAGE_TILING_OPTIMAL, 1090 .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 1091 .flags = 0, 1092 }; 1093 1094 VkImageViewCreateInfo view = { 1095 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 1096 .pNext = NULL, 1097 .image = VK_NULL_HANDLE, 1098 .format = depth_format, 1099 .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, 1100 .baseMipLevel = 0, 1101 .levelCount = 1, 1102 .baseArrayLayer = 0, 1103 .layerCount = 1}, 1104 .flags = 0, 1105 .viewType = VK_IMAGE_VIEW_TYPE_2D, 1106 }; 1107 1108 VkMemoryRequirements mem_reqs; 1109 VkResult U_ASSERT_ONLY err; 1110 bool U_ASSERT_ONLY pass; 1111 1112 demo->depth.format = depth_format; 1113 1114 /* create image */ 1115 err = vkCreateImage(demo->device, &image, NULL, &demo->depth.image); 1116 assert(!err); 1117 1118 vkGetImageMemoryRequirements(demo->device, demo->depth.image, &mem_reqs); 1119 assert(!err); 1120 1121 demo->depth.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 1122 demo->depth.mem_alloc.pNext = NULL; 1123 demo->depth.mem_alloc.allocationSize = mem_reqs.size; 1124 demo->depth.mem_alloc.memoryTypeIndex = 0; 1125 1126 pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, 1127 0, /* No requirements */ 1128 &demo->depth.mem_alloc.memoryTypeIndex); 1129 assert(pass); 1130 1131 /* allocate memory */ 1132 err = vkAllocateMemory(demo->device, &demo->depth.mem_alloc, NULL, 1133 &demo->depth.mem); 1134 assert(!err); 1135 1136 /* bind memory */ 1137 err = 1138 vkBindImageMemory(demo->device, demo->depth.image, demo->depth.mem, 0); 1139 assert(!err); 1140 1141 /* create image view */ 1142 view.image = demo->depth.image; 1143 err = vkCreateImageView(demo->device, &view, NULL, &demo->depth.view); 1144 assert(!err); 1145} 1146 1147/* Load a ppm file into memory */ 1148bool loadTexture(const char *filename, uint8_t *rgba_data, 1149 VkSubresourceLayout *layout, int32_t *width, int32_t *height) { 1150#ifdef __ANDROID__ 1151#include <lunarg.ppm.h> 1152 char *cPtr; 1153 cPtr = (char*)lunarg_ppm; 1154 if ((unsigned char*)cPtr >= (lunarg_ppm + lunarg_ppm_len) || strncmp(cPtr, "P6\n", 3)) { 1155 return false; 1156 } 1157 while(strncmp(cPtr++, "\n", 1)); 1158 sscanf(cPtr, "%u %u", width, height); 1159 if (rgba_data == NULL) { 1160 return true; 1161 } 1162 while(strncmp(cPtr++, "\n", 1)); 1163 if ((unsigned char*)cPtr >= (lunarg_ppm + lunarg_ppm_len) || strncmp(cPtr, "255\n", 4)) { 1164 return false; 1165 } 1166 while(strncmp(cPtr++, "\n", 1)); 1167 1168 for (int y = 0; y < *height; y++) { 1169 uint8_t *rowPtr = rgba_data; 1170 for (int x = 0; x < *width; x++) { 1171 memcpy(rowPtr, cPtr, 3); 1172 rowPtr[3] = 255; /* Alpha of 1 */ 1173 rowPtr += 4; 1174 cPtr += 3; 1175 } 1176 rgba_data += layout->rowPitch; 1177 } 1178 1179 return true; 1180#else 1181 FILE *fPtr = fopen(filename, "rb"); 1182 char header[256], *cPtr, *tmp; 1183 1184 if (!fPtr) 1185 return false; 1186 1187 cPtr = fgets(header, 256, fPtr); // P6 1188 if (cPtr == NULL || strncmp(header, "P6\n", 3)) { 1189 fclose(fPtr); 1190 return false; 1191 } 1192 1193 do { 1194 cPtr = fgets(header, 256, fPtr); 1195 if (cPtr == NULL) { 1196 fclose(fPtr); 1197 return false; 1198 } 1199 } while (!strncmp(header, "#", 1)); 1200 1201 sscanf(header, "%u %u", width, height); 1202 if (rgba_data == NULL) { 1203 fclose(fPtr); 1204 return true; 1205 } 1206 tmp = fgets(header, 256, fPtr); // Format 1207 (void)tmp; 1208 if (cPtr == NULL || strncmp(header, "255\n", 3)) { 1209 fclose(fPtr); 1210 return false; 1211 } 1212 1213 for (int y = 0; y < *height; y++) { 1214 uint8_t *rowPtr = rgba_data; 1215 for (int x = 0; x < *width; x++) { 1216 size_t s = fread(rowPtr, 3, 1, fPtr); 1217 (void)s; 1218 rowPtr[3] = 255; /* Alpha of 1 */ 1219 rowPtr += 4; 1220 } 1221 rgba_data += layout->rowPitch; 1222 } 1223 fclose(fPtr); 1224 return true; 1225#endif 1226} 1227 1228static void demo_prepare_texture_image(struct demo *demo, const char *filename, 1229 struct texture_object *tex_obj, 1230 VkImageTiling tiling, 1231 VkImageUsageFlags usage, 1232 VkFlags required_props) { 1233 const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM; 1234 int32_t tex_width; 1235 int32_t tex_height; 1236 VkResult U_ASSERT_ONLY err; 1237 bool U_ASSERT_ONLY pass; 1238 1239 if (!loadTexture(filename, NULL, NULL, &tex_width, &tex_height)) { 1240 ERR_EXIT("Failed to load textures", "Load Texture Failure"); 1241 } 1242 1243 tex_obj->tex_width = tex_width; 1244 tex_obj->tex_height = tex_height; 1245 1246 const VkImageCreateInfo image_create_info = { 1247 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 1248 .pNext = NULL, 1249 .imageType = VK_IMAGE_TYPE_2D, 1250 .format = tex_format, 1251 .extent = {tex_width, tex_height, 1}, 1252 .mipLevels = 1, 1253 .arrayLayers = 1, 1254 .samples = VK_SAMPLE_COUNT_1_BIT, 1255 .tiling = tiling, 1256 .usage = usage, 1257 .flags = 0, 1258 .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED, 1259 }; 1260 1261 VkMemoryRequirements mem_reqs; 1262 1263 err = 1264 vkCreateImage(demo->device, &image_create_info, NULL, &tex_obj->image); 1265 assert(!err); 1266 1267 vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs); 1268 1269 tex_obj->mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 1270 tex_obj->mem_alloc.pNext = NULL; 1271 tex_obj->mem_alloc.allocationSize = mem_reqs.size; 1272 tex_obj->mem_alloc.memoryTypeIndex = 0; 1273 1274 pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, 1275 required_props, 1276 &tex_obj->mem_alloc.memoryTypeIndex); 1277 assert(pass); 1278 1279 /* allocate memory */ 1280 err = vkAllocateMemory(demo->device, &tex_obj->mem_alloc, NULL, 1281 &(tex_obj->mem)); 1282 assert(!err); 1283 1284 /* bind memory */ 1285 err = vkBindImageMemory(demo->device, tex_obj->image, tex_obj->mem, 0); 1286 assert(!err); 1287 1288 if (required_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { 1289 const VkImageSubresource subres = { 1290 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 1291 .mipLevel = 0, 1292 .arrayLayer = 0, 1293 }; 1294 VkSubresourceLayout layout; 1295 void *data; 1296 1297 vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres, 1298 &layout); 1299 1300 err = vkMapMemory(demo->device, tex_obj->mem, 0, 1301 tex_obj->mem_alloc.allocationSize, 0, &data); 1302 assert(!err); 1303 1304 if (!loadTexture(filename, data, &layout, &tex_width, &tex_height)) { 1305 fprintf(stderr, "Error loading texture: %s\n", filename); 1306 } 1307 1308 vkUnmapMemory(demo->device, tex_obj->mem); 1309 } 1310 1311 tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 1312} 1313 1314static void demo_destroy_texture_image(struct demo *demo, 1315 struct texture_object *tex_objs) { 1316 /* clean up staging resources */ 1317 vkFreeMemory(demo->device, tex_objs->mem, NULL); 1318 vkDestroyImage(demo->device, tex_objs->image, NULL); 1319} 1320 1321static void demo_prepare_textures(struct demo *demo) { 1322 const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM; 1323 VkFormatProperties props; 1324 uint32_t i; 1325 1326 vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props); 1327 1328 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1329 VkResult U_ASSERT_ONLY err; 1330 1331 if ((props.linearTilingFeatures & 1332 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && 1333 !demo->use_staging_buffer) { 1334 /* Device can texture using linear textures */ 1335 demo_prepare_texture_image( 1336 demo, tex_files[i], &demo->textures[i], VK_IMAGE_TILING_LINEAR, 1337 VK_IMAGE_USAGE_SAMPLED_BIT, 1338 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 1339 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); 1340 // Nothing in the pipeline needs to be complete to start, and don't allow fragment 1341 // shader to run until layout transition completes 1342 demo_set_image_layout(demo, demo->textures[i].image, VK_IMAGE_ASPECT_COLOR_BIT, 1343 VK_IMAGE_LAYOUT_PREINITIALIZED, demo->textures[i].imageLayout, 1344 VK_ACCESS_HOST_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 1345 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); 1346 } else if (props.optimalTilingFeatures & 1347 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { 1348 /* Must use staging buffer to copy linear texture to optimized */ 1349 struct texture_object staging_texture; 1350 1351 memset(&staging_texture, 0, sizeof(staging_texture)); 1352 demo_prepare_texture_image( 1353 demo, tex_files[i], &staging_texture, VK_IMAGE_TILING_LINEAR, 1354 VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1355 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 1356 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); 1357 1358 demo_prepare_texture_image( 1359 demo, tex_files[i], &demo->textures[i], VK_IMAGE_TILING_OPTIMAL, 1360 (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT), 1361 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); 1362 1363 demo_set_image_layout(demo, staging_texture.image, 1364 VK_IMAGE_ASPECT_COLOR_BIT, 1365 VK_IMAGE_LAYOUT_PREINITIALIZED, 1366 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1367 VK_ACCESS_HOST_WRITE_BIT, 1368 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 1369 VK_PIPELINE_STAGE_TRANSFER_BIT); 1370 1371 demo_set_image_layout(demo, demo->textures[i].image, 1372 VK_IMAGE_ASPECT_COLOR_BIT, 1373 VK_IMAGE_LAYOUT_PREINITIALIZED, 1374 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1375 VK_ACCESS_HOST_WRITE_BIT, 1376 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 1377 VK_PIPELINE_STAGE_TRANSFER_BIT); 1378 1379 VkImageCopy copy_region = { 1380 .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, 1381 .srcOffset = {0, 0, 0}, 1382 .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, 1383 .dstOffset = {0, 0, 0}, 1384 .extent = {staging_texture.tex_width, 1385 staging_texture.tex_height, 1}, 1386 }; 1387 vkCmdCopyImage( 1388 demo->cmd, staging_texture.image, 1389 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, demo->textures[i].image, 1390 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region); 1391 1392 demo_set_image_layout(demo, demo->textures[i].image, 1393 VK_IMAGE_ASPECT_COLOR_BIT, 1394 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1395 demo->textures[i].imageLayout, 1396 VK_ACCESS_TRANSFER_WRITE_BIT, 1397 VK_PIPELINE_STAGE_TRANSFER_BIT, 1398 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); 1399 1400 demo_flush_init_cmd(demo); 1401 1402 demo_destroy_texture_image(demo, &staging_texture); 1403 } else { 1404 /* Can't support VK_FORMAT_R8G8B8A8_UNORM !? */ 1405 assert(!"No support for R8G8B8A8_UNORM as texture image format"); 1406 } 1407 1408 const VkSamplerCreateInfo sampler = { 1409 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 1410 .pNext = NULL, 1411 .magFilter = VK_FILTER_NEAREST, 1412 .minFilter = VK_FILTER_NEAREST, 1413 .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, 1414 .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 1415 .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 1416 .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 1417 .mipLodBias = 0.0f, 1418 .anisotropyEnable = VK_FALSE, 1419 .maxAnisotropy = 1, 1420 .compareOp = VK_COMPARE_OP_NEVER, 1421 .minLod = 0.0f, 1422 .maxLod = 0.0f, 1423 .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, 1424 .unnormalizedCoordinates = VK_FALSE, 1425 }; 1426 1427 VkImageViewCreateInfo view = { 1428 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 1429 .pNext = NULL, 1430 .image = VK_NULL_HANDLE, 1431 .viewType = VK_IMAGE_VIEW_TYPE_2D, 1432 .format = tex_format, 1433 .components = 1434 { 1435 VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, 1436 VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A, 1437 }, 1438 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}, 1439 .flags = 0, 1440 }; 1441 1442 /* create sampler */ 1443 err = vkCreateSampler(demo->device, &sampler, NULL, 1444 &demo->textures[i].sampler); 1445 assert(!err); 1446 1447 /* create image view */ 1448 view.image = demo->textures[i].image; 1449 err = vkCreateImageView(demo->device, &view, NULL, 1450 &demo->textures[i].view); 1451 assert(!err); 1452 } 1453} 1454 1455void demo_prepare_cube_data_buffer(struct demo *demo) { 1456 VkBufferCreateInfo buf_info; 1457 VkMemoryRequirements mem_reqs; 1458 uint8_t *pData; 1459 int i; 1460 mat4x4 MVP, VP; 1461 VkResult U_ASSERT_ONLY err; 1462 bool U_ASSERT_ONLY pass; 1463 struct vktexcube_vs_uniform data; 1464 1465 mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix); 1466 mat4x4_mul(MVP, VP, demo->model_matrix); 1467 memcpy(data.mvp, MVP, sizeof(MVP)); 1468 // dumpMatrix("MVP", MVP); 1469 1470 for (i = 0; i < 12 * 3; i++) { 1471 data.position[i][0] = g_vertex_buffer_data[i * 3]; 1472 data.position[i][1] = g_vertex_buffer_data[i * 3 + 1]; 1473 data.position[i][2] = g_vertex_buffer_data[i * 3 + 2]; 1474 data.position[i][3] = 1.0f; 1475 data.attr[i][0] = g_uv_buffer_data[2 * i]; 1476 data.attr[i][1] = g_uv_buffer_data[2 * i + 1]; 1477 data.attr[i][2] = 0; 1478 data.attr[i][3] = 0; 1479 } 1480 1481 memset(&buf_info, 0, sizeof(buf_info)); 1482 buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 1483 buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; 1484 buf_info.size = sizeof(data); 1485 err = 1486 vkCreateBuffer(demo->device, &buf_info, NULL, &demo->uniform_data.buf); 1487 assert(!err); 1488 1489 vkGetBufferMemoryRequirements(demo->device, demo->uniform_data.buf, 1490 &mem_reqs); 1491 1492 demo->uniform_data.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 1493 demo->uniform_data.mem_alloc.pNext = NULL; 1494 demo->uniform_data.mem_alloc.allocationSize = mem_reqs.size; 1495 demo->uniform_data.mem_alloc.memoryTypeIndex = 0; 1496 1497 pass = memory_type_from_properties( 1498 demo, mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 1499 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 1500 &demo->uniform_data.mem_alloc.memoryTypeIndex); 1501 assert(pass); 1502 1503 err = vkAllocateMemory(demo->device, &demo->uniform_data.mem_alloc, NULL, 1504 &(demo->uniform_data.mem)); 1505 assert(!err); 1506 1507 err = vkMapMemory(demo->device, demo->uniform_data.mem, 0, 1508 demo->uniform_data.mem_alloc.allocationSize, 0, 1509 (void **)&pData); 1510 assert(!err); 1511 1512 memcpy(pData, &data, sizeof data); 1513 1514 vkUnmapMemory(demo->device, demo->uniform_data.mem); 1515 1516 err = vkBindBufferMemory(demo->device, demo->uniform_data.buf, 1517 demo->uniform_data.mem, 0); 1518 assert(!err); 1519 1520 demo->uniform_data.buffer_info.buffer = demo->uniform_data.buf; 1521 demo->uniform_data.buffer_info.offset = 0; 1522 demo->uniform_data.buffer_info.range = sizeof(data); 1523} 1524 1525static void demo_prepare_descriptor_layout(struct demo *demo) { 1526 const VkDescriptorSetLayoutBinding layout_bindings[2] = { 1527 [0] = 1528 { 1529 .binding = 0, 1530 .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1531 .descriptorCount = 1, 1532 .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, 1533 .pImmutableSamplers = NULL, 1534 }, 1535 [1] = 1536 { 1537 .binding = 1, 1538 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1539 .descriptorCount = DEMO_TEXTURE_COUNT, 1540 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, 1541 .pImmutableSamplers = NULL, 1542 }, 1543 }; 1544 const VkDescriptorSetLayoutCreateInfo descriptor_layout = { 1545 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 1546 .pNext = NULL, 1547 .bindingCount = 2, 1548 .pBindings = layout_bindings, 1549 }; 1550 VkResult U_ASSERT_ONLY err; 1551 1552 err = vkCreateDescriptorSetLayout(demo->device, &descriptor_layout, NULL, 1553 &demo->desc_layout); 1554 assert(!err); 1555 1556 const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = { 1557 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 1558 .pNext = NULL, 1559 .setLayoutCount = 1, 1560 .pSetLayouts = &demo->desc_layout, 1561 }; 1562 1563 err = vkCreatePipelineLayout(demo->device, &pPipelineLayoutCreateInfo, NULL, 1564 &demo->pipeline_layout); 1565 assert(!err); 1566} 1567 1568static void demo_prepare_render_pass(struct demo *demo) { 1569 // The initial layout for the color and depth attachments will be LAYOUT_UNDEFINED 1570 // because at the start of the renderpass, we don't care about their contents. 1571 // At the start of the subpass, the color attachment's layout will be transitioned 1572 // to LAYOUT_COLOR_ATTACHMENT_OPTIMAL and the depth stencil attachment's layout 1573 // will be transitioned to LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL. At the end of 1574 // the renderpass, the color attachment's layout will be transitioned to 1575 // LAYOUT_PRESENT_SRC_KHR to be ready to present. This is all done as part of 1576 // the renderpass, no barriers are necessary. 1577 const VkAttachmentDescription attachments[2] = { 1578 [0] = 1579 { 1580 .format = demo->format, 1581 .samples = VK_SAMPLE_COUNT_1_BIT, 1582 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 1583 .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 1584 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 1585 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1586 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 1587 .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 1588 }, 1589 [1] = 1590 { 1591 .format = demo->depth.format, 1592 .samples = VK_SAMPLE_COUNT_1_BIT, 1593 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 1594 .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1595 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 1596 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1597 .initialLayout = 1598 VK_IMAGE_LAYOUT_UNDEFINED, 1599 .finalLayout = 1600 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1601 }, 1602 }; 1603 const VkAttachmentReference color_reference = { 1604 .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1605 }; 1606 const VkAttachmentReference depth_reference = { 1607 .attachment = 1, 1608 .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1609 }; 1610 const VkSubpassDescription subpass = { 1611 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, 1612 .flags = 0, 1613 .inputAttachmentCount = 0, 1614 .pInputAttachments = NULL, 1615 .colorAttachmentCount = 1, 1616 .pColorAttachments = &color_reference, 1617 .pResolveAttachments = NULL, 1618 .pDepthStencilAttachment = &depth_reference, 1619 .preserveAttachmentCount = 0, 1620 .pPreserveAttachments = NULL, 1621 }; 1622 const VkRenderPassCreateInfo rp_info = { 1623 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 1624 .pNext = NULL, 1625 .attachmentCount = 2, 1626 .pAttachments = attachments, 1627 .subpassCount = 1, 1628 .pSubpasses = &subpass, 1629 .dependencyCount = 0, 1630 .pDependencies = NULL, 1631 }; 1632 VkResult U_ASSERT_ONLY err; 1633 1634 err = vkCreateRenderPass(demo->device, &rp_info, NULL, &demo->render_pass); 1635 assert(!err); 1636} 1637 1638//TODO: Merge shader reading 1639#ifndef __ANDROID__ 1640static VkShaderModule 1641demo_prepare_shader_module(struct demo *demo, const void *code, size_t size) { 1642 VkShaderModule module; 1643 VkShaderModuleCreateInfo moduleCreateInfo; 1644 VkResult U_ASSERT_ONLY err; 1645 1646 moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 1647 moduleCreateInfo.pNext = NULL; 1648 1649 moduleCreateInfo.codeSize = size; 1650 moduleCreateInfo.pCode = code; 1651 moduleCreateInfo.flags = 0; 1652 err = vkCreateShaderModule(demo->device, &moduleCreateInfo, NULL, &module); 1653 assert(!err); 1654 1655 return module; 1656} 1657 1658char *demo_read_spv(const char *filename, size_t *psize) { 1659 long int size; 1660 size_t U_ASSERT_ONLY retval; 1661 void *shader_code; 1662 1663 FILE *fp = fopen(filename, "rb"); 1664 if (!fp) 1665 return NULL; 1666 1667 fseek(fp, 0L, SEEK_END); 1668 size = ftell(fp); 1669 1670 fseek(fp, 0L, SEEK_SET); 1671 1672 shader_code = malloc(size); 1673 retval = fread(shader_code, size, 1, fp); 1674 assert(retval == 1); 1675 1676 *psize = size; 1677 1678 fclose(fp); 1679 return shader_code; 1680} 1681#endif 1682 1683static VkShaderModule demo_prepare_vs(struct demo *demo) { 1684#ifdef __ANDROID__ 1685 VkShaderModuleCreateInfo sh_info = {}; 1686 sh_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 1687 1688#include "cube.vert.h" 1689 sh_info.codeSize = sizeof(cube_vert); 1690 sh_info.pCode = cube_vert; 1691 VkResult U_ASSERT_ONLY err = vkCreateShaderModule(demo->device, &sh_info, NULL, &demo->vert_shader_module); 1692 assert(!err); 1693#else 1694 void *vertShaderCode; 1695 size_t size; 1696 1697 vertShaderCode = demo_read_spv("cube-vert.spv", &size); 1698 1699 demo->vert_shader_module = 1700 demo_prepare_shader_module(demo, vertShaderCode, size); 1701 1702 free(vertShaderCode); 1703#endif 1704 1705 return demo->vert_shader_module; 1706} 1707 1708static VkShaderModule demo_prepare_fs(struct demo *demo) { 1709#ifdef __ANDROID__ 1710 VkShaderModuleCreateInfo sh_info = {}; 1711 sh_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 1712 1713#include "cube.frag.h" 1714 sh_info.codeSize = sizeof(cube_frag); 1715 sh_info.pCode = cube_frag; 1716 VkResult U_ASSERT_ONLY err = vkCreateShaderModule(demo->device, &sh_info, NULL, &demo->frag_shader_module); 1717 assert(!err); 1718#else 1719 void *fragShaderCode; 1720 size_t size; 1721 1722 fragShaderCode = demo_read_spv("cube-frag.spv", &size); 1723 1724 demo->frag_shader_module = 1725 demo_prepare_shader_module(demo, fragShaderCode, size); 1726 1727 free(fragShaderCode); 1728#endif 1729 1730 return demo->frag_shader_module; 1731} 1732 1733static void demo_prepare_pipeline(struct demo *demo) { 1734 VkGraphicsPipelineCreateInfo pipeline; 1735 VkPipelineCacheCreateInfo pipelineCache; 1736 VkPipelineVertexInputStateCreateInfo vi; 1737 VkPipelineInputAssemblyStateCreateInfo ia; 1738 VkPipelineRasterizationStateCreateInfo rs; 1739 VkPipelineColorBlendStateCreateInfo cb; 1740 VkPipelineDepthStencilStateCreateInfo ds; 1741 VkPipelineViewportStateCreateInfo vp; 1742 VkPipelineMultisampleStateCreateInfo ms; 1743 VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE]; 1744 VkPipelineDynamicStateCreateInfo dynamicState; 1745 VkResult U_ASSERT_ONLY err; 1746 1747 memset(dynamicStateEnables, 0, sizeof dynamicStateEnables); 1748 memset(&dynamicState, 0, sizeof dynamicState); 1749 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; 1750 dynamicState.pDynamicStates = dynamicStateEnables; 1751 1752 memset(&pipeline, 0, sizeof(pipeline)); 1753 pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 1754 pipeline.layout = demo->pipeline_layout; 1755 1756 memset(&vi, 0, sizeof(vi)); 1757 vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 1758 1759 memset(&ia, 0, sizeof(ia)); 1760 ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 1761 ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 1762 1763 memset(&rs, 0, sizeof(rs)); 1764 rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; 1765 rs.polygonMode = VK_POLYGON_MODE_FILL; 1766 rs.cullMode = VK_CULL_MODE_BACK_BIT; 1767 rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; 1768 rs.depthClampEnable = VK_FALSE; 1769 rs.rasterizerDiscardEnable = VK_FALSE; 1770 rs.depthBiasEnable = VK_FALSE; 1771 rs.lineWidth = 1.0f; 1772 1773 memset(&cb, 0, sizeof(cb)); 1774 cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 1775 VkPipelineColorBlendAttachmentState att_state[1]; 1776 memset(att_state, 0, sizeof(att_state)); 1777 att_state[0].colorWriteMask = 0xf; 1778 att_state[0].blendEnable = VK_FALSE; 1779 cb.attachmentCount = 1; 1780 cb.pAttachments = att_state; 1781 1782 memset(&vp, 0, sizeof(vp)); 1783 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 1784 vp.viewportCount = 1; 1785 dynamicStateEnables[dynamicState.dynamicStateCount++] = 1786 VK_DYNAMIC_STATE_VIEWPORT; 1787 vp.scissorCount = 1; 1788 dynamicStateEnables[dynamicState.dynamicStateCount++] = 1789 VK_DYNAMIC_STATE_SCISSOR; 1790 1791 memset(&ds, 0, sizeof(ds)); 1792 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; 1793 ds.depthTestEnable = VK_TRUE; 1794 ds.depthWriteEnable = VK_TRUE; 1795 ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; 1796 ds.depthBoundsTestEnable = VK_FALSE; 1797 ds.back.failOp = VK_STENCIL_OP_KEEP; 1798 ds.back.passOp = VK_STENCIL_OP_KEEP; 1799 ds.back.compareOp = VK_COMPARE_OP_ALWAYS; 1800 ds.stencilTestEnable = VK_FALSE; 1801 ds.front = ds.back; 1802 1803 memset(&ms, 0, sizeof(ms)); 1804 ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 1805 ms.pSampleMask = NULL; 1806 ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; 1807 1808 // Two stages: vs and fs 1809 pipeline.stageCount = 2; 1810 VkPipelineShaderStageCreateInfo shaderStages[2]; 1811 memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo)); 1812 1813 shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1814 shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; 1815 shaderStages[0].module = demo_prepare_vs(demo); 1816 shaderStages[0].pName = "main"; 1817 1818 shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1819 shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; 1820 shaderStages[1].module = demo_prepare_fs(demo); 1821 shaderStages[1].pName = "main"; 1822 1823 memset(&pipelineCache, 0, sizeof(pipelineCache)); 1824 pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; 1825 1826 err = vkCreatePipelineCache(demo->device, &pipelineCache, NULL, 1827 &demo->pipelineCache); 1828 assert(!err); 1829 1830 pipeline.pVertexInputState = &vi; 1831 pipeline.pInputAssemblyState = &ia; 1832 pipeline.pRasterizationState = &rs; 1833 pipeline.pColorBlendState = &cb; 1834 pipeline.pMultisampleState = &ms; 1835 pipeline.pViewportState = &vp; 1836 pipeline.pDepthStencilState = &ds; 1837 pipeline.pStages = shaderStages; 1838 pipeline.renderPass = demo->render_pass; 1839 pipeline.pDynamicState = &dynamicState; 1840 1841 pipeline.renderPass = demo->render_pass; 1842 1843 err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1, 1844 &pipeline, NULL, &demo->pipeline); 1845 assert(!err); 1846 1847 vkDestroyShaderModule(demo->device, demo->frag_shader_module, NULL); 1848 vkDestroyShaderModule(demo->device, demo->vert_shader_module, NULL); 1849} 1850 1851static void demo_prepare_descriptor_pool(struct demo *demo) { 1852 const VkDescriptorPoolSize type_counts[2] = { 1853 [0] = 1854 { 1855 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1856 .descriptorCount = 1, 1857 }, 1858 [1] = 1859 { 1860 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1861 .descriptorCount = DEMO_TEXTURE_COUNT, 1862 }, 1863 }; 1864 const VkDescriptorPoolCreateInfo descriptor_pool = { 1865 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 1866 .pNext = NULL, 1867 .maxSets = 1, 1868 .poolSizeCount = 2, 1869 .pPoolSizes = type_counts, 1870 }; 1871 VkResult U_ASSERT_ONLY err; 1872 1873 err = vkCreateDescriptorPool(demo->device, &descriptor_pool, NULL, 1874 &demo->desc_pool); 1875 assert(!err); 1876} 1877 1878static void demo_prepare_descriptor_set(struct demo *demo) { 1879 VkDescriptorImageInfo tex_descs[DEMO_TEXTURE_COUNT]; 1880 VkWriteDescriptorSet writes[2]; 1881 VkResult U_ASSERT_ONLY err; 1882 uint32_t i; 1883 1884 VkDescriptorSetAllocateInfo alloc_info = { 1885 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 1886 .pNext = NULL, 1887 .descriptorPool = demo->desc_pool, 1888 .descriptorSetCount = 1, 1889 .pSetLayouts = &demo->desc_layout}; 1890 err = vkAllocateDescriptorSets(demo->device, &alloc_info, &demo->desc_set); 1891 assert(!err); 1892 1893 memset(&tex_descs, 0, sizeof(tex_descs)); 1894 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1895 tex_descs[i].sampler = demo->textures[i].sampler; 1896 tex_descs[i].imageView = demo->textures[i].view; 1897 tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 1898 } 1899 1900 memset(&writes, 0, sizeof(writes)); 1901 1902 writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 1903 writes[0].dstSet = demo->desc_set; 1904 writes[0].descriptorCount = 1; 1905 writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 1906 writes[0].pBufferInfo = &demo->uniform_data.buffer_info; 1907 1908 writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 1909 writes[1].dstSet = demo->desc_set; 1910 writes[1].dstBinding = 1; 1911 writes[1].descriptorCount = DEMO_TEXTURE_COUNT; 1912 writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 1913 writes[1].pImageInfo = tex_descs; 1914 1915 vkUpdateDescriptorSets(demo->device, 2, writes, 0, NULL); 1916} 1917 1918static void demo_prepare_framebuffers(struct demo *demo) { 1919 VkImageView attachments[2]; 1920 attachments[1] = demo->depth.view; 1921 1922 const VkFramebufferCreateInfo fb_info = { 1923 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 1924 .pNext = NULL, 1925 .renderPass = demo->render_pass, 1926 .attachmentCount = 2, 1927 .pAttachments = attachments, 1928 .width = demo->width, 1929 .height = demo->height, 1930 .layers = 1, 1931 }; 1932 VkResult U_ASSERT_ONLY err; 1933 uint32_t i; 1934 1935 demo->framebuffers = (VkFramebuffer *)malloc(demo->swapchainImageCount * 1936 sizeof(VkFramebuffer)); 1937 assert(demo->framebuffers); 1938 1939 for (i = 0; i < demo->swapchainImageCount; i++) { 1940 attachments[0] = demo->buffers[i].view; 1941 err = vkCreateFramebuffer(demo->device, &fb_info, NULL, 1942 &demo->framebuffers[i]); 1943 assert(!err); 1944 } 1945} 1946 1947static void demo_prepare(struct demo *demo) { 1948 VkResult U_ASSERT_ONLY err; 1949 1950 const VkCommandPoolCreateInfo cmd_pool_info = { 1951 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 1952 .pNext = NULL, 1953 .queueFamilyIndex = demo->graphics_queue_family_index, 1954 .flags = 0, 1955 }; 1956 err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL, 1957 &demo->cmd_pool); 1958 assert(!err); 1959 1960 const VkCommandBufferAllocateInfo cmd = { 1961 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 1962 .pNext = NULL, 1963 .commandPool = demo->cmd_pool, 1964 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1965 .commandBufferCount = 1, 1966 }; 1967 1968 demo_prepare_buffers(demo); 1969 demo_prepare_depth(demo); 1970 demo_prepare_textures(demo); 1971 demo_prepare_cube_data_buffer(demo); 1972 1973 demo_prepare_descriptor_layout(demo); 1974 demo_prepare_render_pass(demo); 1975 demo_prepare_pipeline(demo); 1976 1977 for (uint32_t i = 0; i < demo->swapchainImageCount; i++) { 1978 err = 1979 vkAllocateCommandBuffers(demo->device, &cmd, &demo->buffers[i].cmd); 1980 assert(!err); 1981 } 1982 1983 if (demo->separate_present_queue) { 1984 const VkCommandPoolCreateInfo cmd_pool_info = { 1985 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 1986 .pNext = NULL, 1987 .queueFamilyIndex = demo->present_queue_family_index, 1988 .flags = 0, 1989 }; 1990 err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL, 1991 &demo->present_cmd_pool); 1992 assert(!err); 1993 const VkCommandBufferAllocateInfo cmd = { 1994 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 1995 .pNext = NULL, 1996 .commandPool = demo->present_cmd_pool, 1997 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1998 .commandBufferCount = 1, 1999 }; 2000 for (uint32_t i = 0; i < demo->swapchainImageCount; i++) { 2001 err = vkAllocateCommandBuffers( 2002 demo->device, &cmd, &demo->buffers[i].graphics_to_present_cmd); 2003 assert(!err); 2004 demo_build_image_ownership_cmd(demo, i); 2005 } 2006 } 2007 2008 demo_prepare_descriptor_pool(demo); 2009 demo_prepare_descriptor_set(demo); 2010 2011 demo_prepare_framebuffers(demo); 2012 2013 for (uint32_t i = 0; i < demo->swapchainImageCount; i++) { 2014 demo->current_buffer = i; 2015 demo_draw_build_cmd(demo, demo->buffers[i].cmd); 2016 } 2017 2018 /* 2019 * Prepare functions above may generate pipeline commands 2020 * that need to be flushed before beginning the render loop. 2021 */ 2022 demo_flush_init_cmd(demo); 2023 2024 demo->current_buffer = 0; 2025 demo->prepared = true; 2026} 2027 2028static void demo_cleanup(struct demo *demo) { 2029 uint32_t i; 2030 2031 demo->prepared = false; 2032 vkDeviceWaitIdle(demo->device); 2033 2034 // Wait for fences from present operations 2035 for (i = 0; i < FRAME_LAG; i++) { 2036 vkWaitForFences(demo->device, 1, &demo->fences[i], VK_TRUE, UINT64_MAX); 2037 vkDestroyFence(demo->device, demo->fences[i], NULL); 2038 vkDestroySemaphore(demo->device, demo->image_acquired_semaphores[i], NULL); 2039 vkDestroySemaphore(demo->device, demo->draw_complete_semaphores[i], NULL); 2040 if (demo->separate_present_queue) { 2041 vkDestroySemaphore(demo->device, demo->image_ownership_semaphores[i], NULL); 2042 } 2043 } 2044 2045 for (i = 0; i < demo->swapchainImageCount; i++) { 2046 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL); 2047 } 2048 free(demo->framebuffers); 2049 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL); 2050 2051 vkDestroyPipeline(demo->device, demo->pipeline, NULL); 2052 vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL); 2053 vkDestroyRenderPass(demo->device, demo->render_pass, NULL); 2054 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL); 2055 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL); 2056 2057 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 2058 vkDestroyImageView(demo->device, demo->textures[i].view, NULL); 2059 vkDestroyImage(demo->device, demo->textures[i].image, NULL); 2060 vkFreeMemory(demo->device, demo->textures[i].mem, NULL); 2061 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL); 2062 } 2063 demo->fpDestroySwapchainKHR(demo->device, demo->swapchain, NULL); 2064 2065 vkDestroyImageView(demo->device, demo->depth.view, NULL); 2066 vkDestroyImage(demo->device, demo->depth.image, NULL); 2067 vkFreeMemory(demo->device, demo->depth.mem, NULL); 2068 2069 vkDestroyBuffer(demo->device, demo->uniform_data.buf, NULL); 2070 vkFreeMemory(demo->device, demo->uniform_data.mem, NULL); 2071 2072 for (i = 0; i < demo->swapchainImageCount; i++) { 2073 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL); 2074 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, 2075 &demo->buffers[i].cmd); 2076 } 2077 free(demo->buffers); 2078 free(demo->queue_props); 2079 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL); 2080 2081 if (demo->separate_present_queue) { 2082 vkDestroyCommandPool(demo->device, demo->present_cmd_pool, NULL); 2083 } 2084 vkDestroyDevice(demo->device, NULL); 2085 if (demo->validate) { 2086 demo->DestroyDebugReportCallback(demo->inst, demo->msg_callback, NULL); 2087 } 2088 vkDestroySurfaceKHR(demo->inst, demo->surface, NULL); 2089 vkDestroyInstance(demo->inst, NULL); 2090 2091#if defined(VK_USE_PLATFORM_XLIB_KHR) 2092 if (demo->use_xlib) { 2093 XDestroyWindow(demo->display, demo->xlib_window); 2094 XCloseDisplay(demo->display); 2095 } else { 2096 xcb_destroy_window(demo->connection, demo->xcb_window); 2097 xcb_disconnect(demo->connection); 2098 } 2099 free(demo->atom_wm_delete_window); 2100#elif defined(VK_USE_PLATFORM_XCB_KHR) 2101 xcb_destroy_window(demo->connection, demo->xcb_window); 2102 xcb_disconnect(demo->connection); 2103 free(demo->atom_wm_delete_window); 2104#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) 2105 wl_shell_surface_destroy(demo->shell_surface); 2106 wl_surface_destroy(demo->window); 2107 wl_shell_destroy(demo->shell); 2108 wl_compositor_destroy(demo->compositor); 2109 wl_registry_destroy(demo->registry); 2110 wl_display_disconnect(demo->display); 2111#endif 2112} 2113 2114static void demo_resize(struct demo *demo) { 2115 uint32_t i; 2116 2117 // Don't react to resize until after first initialization. 2118 if (!demo->prepared) { 2119 return; 2120 } 2121 // In order to properly resize the window, we must re-create the swapchain 2122 // AND redo the command buffers, etc. 2123 // 2124 // First, perform part of the demo_cleanup() function: 2125 demo->prepared = false; 2126 vkDeviceWaitIdle(demo->device); 2127 2128 for (i = 0; i < demo->swapchainImageCount; i++) { 2129 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL); 2130 } 2131 free(demo->framebuffers); 2132 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL); 2133 2134 vkDestroyPipeline(demo->device, demo->pipeline, NULL); 2135 vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL); 2136 vkDestroyRenderPass(demo->device, demo->render_pass, NULL); 2137 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL); 2138 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL); 2139 2140 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 2141 vkDestroyImageView(demo->device, demo->textures[i].view, NULL); 2142 vkDestroyImage(demo->device, demo->textures[i].image, NULL); 2143 vkFreeMemory(demo->device, demo->textures[i].mem, NULL); 2144 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL); 2145 } 2146 2147 vkDestroyImageView(demo->device, demo->depth.view, NULL); 2148 vkDestroyImage(demo->device, demo->depth.image, NULL); 2149 vkFreeMemory(demo->device, demo->depth.mem, NULL); 2150 2151 vkDestroyBuffer(demo->device, demo->uniform_data.buf, NULL); 2152 vkFreeMemory(demo->device, demo->uniform_data.mem, NULL); 2153 2154 for (i = 0; i < demo->swapchainImageCount; i++) { 2155 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL); 2156 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, 2157 &demo->buffers[i].cmd); 2158 } 2159 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL); 2160 if (demo->separate_present_queue) { 2161 vkDestroyCommandPool(demo->device, demo->present_cmd_pool, NULL); 2162 } 2163 free(demo->buffers); 2164 2165 // Second, re-perform the demo_prepare() function, which will re-create the 2166 // swapchain: 2167 demo_prepare(demo); 2168} 2169 2170// On MS-Windows, make this a global, so it's available to WndProc() 2171struct demo demo; 2172 2173#if defined(VK_USE_PLATFORM_WIN32_KHR) 2174static void demo_run(struct demo *demo) { 2175 if (!demo->prepared) 2176 return; 2177 2178 demo_update_data_buffer(demo); 2179 demo_draw(demo); 2180 demo->curFrame++; 2181 if (demo->frameCount != INT_MAX && demo->curFrame == demo->frameCount) { 2182 PostQuitMessage(validation_error); 2183 } 2184} 2185 2186// MS-Windows event handling function: 2187LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 2188 switch (uMsg) { 2189 case WM_CLOSE: 2190 PostQuitMessage(validation_error); 2191 break; 2192 case WM_PAINT: 2193 // The validation callback calls MessageBox which can generate paint 2194 // events - don't make more Vulkan calls if we got here from the 2195 // callback 2196 if (!in_callback) { 2197 demo_run(&demo); 2198 } 2199 break; 2200 case WM_GETMINMAXINFO: // set window's minimum size 2201 ((MINMAXINFO*)lParam)->ptMinTrackSize = demo.minsize; 2202 return 0; 2203 case WM_SIZE: 2204 // Resize the application to the new window size, except when 2205 // it was minimized. Vulkan doesn't support images or swapchains 2206 // with width=0 and height=0. 2207 if (wParam != SIZE_MINIMIZED) { 2208 demo.width = lParam & 0xffff; 2209 demo.height = (lParam & 0xffff0000) >> 16; 2210 demo_resize(&demo); 2211 } 2212 break; 2213 default: 2214 break; 2215 } 2216 return (DefWindowProc(hWnd, uMsg, wParam, lParam)); 2217} 2218 2219static void demo_create_window(struct demo *demo) { 2220 WNDCLASSEX win_class; 2221 2222 // Initialize the window class structure: 2223 win_class.cbSize = sizeof(WNDCLASSEX); 2224 win_class.style = CS_HREDRAW | CS_VREDRAW; 2225 win_class.lpfnWndProc = WndProc; 2226 win_class.cbClsExtra = 0; 2227 win_class.cbWndExtra = 0; 2228 win_class.hInstance = demo->connection; // hInstance 2229 win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); 2230 win_class.hCursor = LoadCursor(NULL, IDC_ARROW); 2231 win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 2232 win_class.lpszMenuName = NULL; 2233 win_class.lpszClassName = demo->name; 2234 win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO); 2235 // Register window class: 2236 if (!RegisterClassEx(&win_class)) { 2237 // It didn't work, so try to give a useful error: 2238 printf("Unexpected error trying to start the application!\n"); 2239 fflush(stdout); 2240 exit(1); 2241 } 2242 // Create window with the registered class: 2243 RECT wr = {0, 0, demo->width, demo->height}; 2244 AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); 2245 demo->window = CreateWindowEx(0, 2246 demo->name, // class name 2247 demo->name, // app name 2248 WS_OVERLAPPEDWINDOW | // window style 2249 WS_VISIBLE | WS_SYSMENU, 2250 100, 100, // x/y coords 2251 wr.right - wr.left, // width 2252 wr.bottom - wr.top, // height 2253 NULL, // handle to parent 2254 NULL, // handle to menu 2255 demo->connection, // hInstance 2256 NULL); // no extra parameters 2257 if (!demo->window) { 2258 // It didn't work, so try to give a useful error: 2259 printf("Cannot create a window in which to draw!\n"); 2260 fflush(stdout); 2261 exit(1); 2262 } 2263 // Window client area size must be at least 1 pixel high, to prevent crash. 2264 demo->minsize.x = GetSystemMetrics(SM_CXMINTRACK); 2265 demo->minsize.y = GetSystemMetrics(SM_CYMINTRACK)+1; 2266} 2267#elif defined(VK_USE_PLATFORM_XLIB_KHR) 2268static void demo_create_xlib_window(struct demo *demo) { 2269 2270 demo->display = XOpenDisplay(NULL); 2271 long visualMask = VisualScreenMask; 2272 int numberOfVisuals; 2273 XVisualInfo vInfoTemplate={}; 2274 vInfoTemplate.screen = DefaultScreen(demo->display); 2275 XVisualInfo *visualInfo = XGetVisualInfo(demo->display, visualMask, 2276 &vInfoTemplate, &numberOfVisuals); 2277 2278 Colormap colormap = XCreateColormap( 2279 demo->display, RootWindow(demo->display, vInfoTemplate.screen), 2280 visualInfo->visual, AllocNone); 2281 2282 XSetWindowAttributes windowAttributes={}; 2283 windowAttributes.colormap = colormap; 2284 windowAttributes.background_pixel = 0xFFFFFFFF; 2285 windowAttributes.border_pixel = 0; 2286 windowAttributes.event_mask = 2287 KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask; 2288 2289 demo->xlib_window = XCreateWindow( 2290 demo->display, RootWindow(demo->display, vInfoTemplate.screen), 0, 0, 2291 demo->width, demo->height, 0, visualInfo->depth, InputOutput, 2292 visualInfo->visual, 2293 CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, &windowAttributes); 2294 2295 XSelectInput(demo->display, demo->xlib_window, ExposureMask | KeyPressMask); 2296 XMapWindow(demo->display, demo->xlib_window); 2297 XFlush(demo->display); 2298 demo->xlib_wm_delete_window = 2299 XInternAtom(demo->display, "WM_DELETE_WINDOW", False); 2300} 2301static void demo_handle_xlib_event(struct demo *demo, const XEvent *event) { 2302 switch(event->type) { 2303 case ClientMessage: 2304 if ((Atom)event->xclient.data.l[0] == demo->xlib_wm_delete_window) 2305 demo->quit = true; 2306 break; 2307 case KeyPress: 2308 switch (event->xkey.keycode) { 2309 case 0x9: // Escape 2310 demo->quit = true; 2311 break; 2312 case 0x71: // left arrow key 2313 demo->spin_angle += demo->spin_increment; 2314 break; 2315 case 0x72: // right arrow key 2316 demo->spin_angle -= demo->spin_increment; 2317 break; 2318 case 0x41: 2319 demo->pause = !demo->pause; 2320 break; 2321 } 2322 break; 2323 case ConfigureNotify: 2324 if ((demo->width != event->xconfigure.width) || 2325 (demo->height != event->xconfigure.height)) { 2326 demo->width = event->xconfigure.width; 2327 demo->height = event->xconfigure.height; 2328 demo_resize(demo); 2329 } 2330 break; 2331 default: 2332 break; 2333 } 2334 2335} 2336 2337static void demo_run_xlib(struct demo *demo) { 2338 2339 while (!demo->quit) { 2340 XEvent event; 2341 2342 if (demo->pause) { 2343 XNextEvent(demo->display, &event); 2344 demo_handle_xlib_event(demo, &event); 2345 } else { 2346 while (XPending(demo->display) > 0) { 2347 XNextEvent(demo->display, &event); 2348 demo_handle_xlib_event(demo, &event); 2349 } 2350 } 2351 2352 demo_update_data_buffer(demo); 2353 demo_draw(demo); 2354 demo->curFrame++; 2355 if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) 2356 demo->quit = true; 2357 } 2358} 2359#endif // VK_USE_PLATFORM_XLIB_KHR 2360#ifdef VK_USE_PLATFORM_XCB_KHR 2361static void demo_handle_xcb_event(struct demo *demo, 2362 const xcb_generic_event_t *event) { 2363 uint8_t event_code = event->response_type & 0x7f; 2364 switch (event_code) { 2365 case XCB_EXPOSE: 2366 // TODO: Resize window 2367 break; 2368 case XCB_CLIENT_MESSAGE: 2369 if ((*(xcb_client_message_event_t *)event).data.data32[0] == 2370 (*demo->atom_wm_delete_window).atom) { 2371 demo->quit = true; 2372 } 2373 break; 2374 case XCB_KEY_RELEASE: { 2375 const xcb_key_release_event_t *key = 2376 (const xcb_key_release_event_t *)event; 2377 2378 switch (key->detail) { 2379 case 0x9: // Escape 2380 demo->quit = true; 2381 break; 2382 case 0x71: // left arrow key 2383 demo->spin_angle += demo->spin_increment; 2384 break; 2385 case 0x72: // right arrow key 2386 demo->spin_angle -= demo->spin_increment; 2387 break; 2388 case 0x41: 2389 demo->pause = !demo->pause; 2390 break; 2391 } 2392 } break; 2393 case XCB_CONFIGURE_NOTIFY: { 2394 const xcb_configure_notify_event_t *cfg = 2395 (const xcb_configure_notify_event_t *)event; 2396 if ((demo->width != cfg->width) || (demo->height != cfg->height)) { 2397 demo->width = cfg->width; 2398 demo->height = cfg->height; 2399 demo_resize(demo); 2400 } 2401 } break; 2402 default: 2403 break; 2404 } 2405} 2406 2407static void demo_run_xcb(struct demo *demo) { 2408 xcb_flush(demo->connection); 2409 2410 while (!demo->quit) { 2411 xcb_generic_event_t *event; 2412 2413 if (demo->pause) { 2414 event = xcb_wait_for_event(demo->connection); 2415 } else { 2416 event = xcb_poll_for_event(demo->connection); 2417 while(event) { 2418 demo_handle_xcb_event(demo, event); 2419 free(event); 2420 event = xcb_poll_for_event(demo->connection); 2421 } 2422 } 2423 2424 demo_update_data_buffer(demo); 2425 demo_draw(demo); 2426 demo->curFrame++; 2427 if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) 2428 demo->quit = true; 2429 } 2430} 2431 2432static void demo_create_xcb_window(struct demo *demo) { 2433 uint32_t value_mask, value_list[32]; 2434 2435 demo->xcb_window = xcb_generate_id(demo->connection); 2436 2437 value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 2438 value_list[0] = demo->screen->black_pixel; 2439 value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE | 2440 XCB_EVENT_MASK_STRUCTURE_NOTIFY; 2441 2442 xcb_create_window(demo->connection, XCB_COPY_FROM_PARENT, demo->xcb_window, 2443 demo->screen->root, 0, 0, demo->width, demo->height, 0, 2444 XCB_WINDOW_CLASS_INPUT_OUTPUT, demo->screen->root_visual, 2445 value_mask, value_list); 2446 2447 /* Magic code that will send notification when window is destroyed */ 2448 xcb_intern_atom_cookie_t cookie = 2449 xcb_intern_atom(demo->connection, 1, 12, "WM_PROTOCOLS"); 2450 xcb_intern_atom_reply_t *reply = 2451 xcb_intern_atom_reply(demo->connection, cookie, 0); 2452 2453 xcb_intern_atom_cookie_t cookie2 = 2454 xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW"); 2455 demo->atom_wm_delete_window = 2456 xcb_intern_atom_reply(demo->connection, cookie2, 0); 2457 2458 xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, demo->xcb_window, 2459 (*reply).atom, 4, 32, 1, 2460 &(*demo->atom_wm_delete_window).atom); 2461 free(reply); 2462 2463 xcb_map_window(demo->connection, demo->xcb_window); 2464 2465 // Force the x/y coordinates to 100,100 results are identical in consecutive 2466 // runs 2467 const uint32_t coords[] = {100, 100}; 2468 xcb_configure_window(demo->connection, demo->xcb_window, 2469 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords); 2470} 2471// VK_USE_PLATFORM_XCB_KHR 2472#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) 2473static void demo_run(struct demo *demo) { 2474 while (!demo->quit) { 2475 demo_update_data_buffer(demo); 2476 demo_draw(demo); 2477 demo->curFrame++; 2478 if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) 2479 demo->quit = true; 2480 } 2481} 2482 2483static void handle_ping(void *data UNUSED, 2484 struct wl_shell_surface *shell_surface, 2485 uint32_t serial) { 2486 wl_shell_surface_pong(shell_surface, serial); 2487} 2488 2489static void handle_configure(void *data UNUSED, 2490 struct wl_shell_surface *shell_surface UNUSED, 2491 uint32_t edges UNUSED, int32_t width UNUSED, 2492 int32_t height UNUSED) {} 2493 2494static void handle_popup_done(void *data UNUSED, 2495 struct wl_shell_surface *shell_surface UNUSED) {} 2496 2497static const struct wl_shell_surface_listener shell_surface_listener = { 2498 handle_ping, handle_configure, handle_popup_done}; 2499 2500static void demo_create_window(struct demo *demo) { 2501 demo->window = wl_compositor_create_surface(demo->compositor); 2502 if (!demo->window) { 2503 printf("Can not create wayland_surface from compositor!\n"); 2504 fflush(stdout); 2505 exit(1); 2506 } 2507 2508 demo->shell_surface = wl_shell_get_shell_surface(demo->shell, demo->window); 2509 if (!demo->shell_surface) { 2510 printf("Can not get shell_surface from wayland_surface!\n"); 2511 fflush(stdout); 2512 exit(1); 2513 } 2514 wl_shell_surface_add_listener(demo->shell_surface, &shell_surface_listener, 2515 demo); 2516 wl_shell_surface_set_toplevel(demo->shell_surface); 2517 wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME); 2518} 2519#elif defined(VK_USE_PLATFORM_ANDROID_KHR) 2520static void demo_run(struct demo *demo) { 2521 if (!demo->prepared) 2522 return; 2523 2524 demo_update_data_buffer(demo); 2525 demo_draw(demo); 2526 demo->curFrame++; 2527} 2528#endif 2529 2530/* 2531 * Return 1 (true) if all layer names specified in check_names 2532 * can be found in given layer properties. 2533 */ 2534static VkBool32 demo_check_layers(uint32_t check_count, char **check_names, 2535 uint32_t layer_count, 2536 VkLayerProperties *layers) { 2537 for (uint32_t i = 0; i < check_count; i++) { 2538 VkBool32 found = 0; 2539 for (uint32_t j = 0; j < layer_count; j++) { 2540 if (!strcmp(check_names[i], layers[j].layerName)) { 2541 found = 1; 2542 break; 2543 } 2544 } 2545 if (!found) { 2546 fprintf(stderr, "Cannot find layer: %s\n", check_names[i]); 2547 return 0; 2548 } 2549 } 2550 return 1; 2551} 2552 2553static void demo_init_vk(struct demo *demo) { 2554 VkResult err; 2555 uint32_t instance_extension_count = 0; 2556 uint32_t instance_layer_count = 0; 2557 uint32_t validation_layer_count = 0; 2558 char **instance_validation_layers = NULL; 2559 demo->enabled_extension_count = 0; 2560 demo->enabled_layer_count = 0; 2561 2562 char *instance_validation_layers_alt1[] = { 2563 "VK_LAYER_LUNARG_standard_validation" 2564 }; 2565 2566 char *instance_validation_layers_alt2[] = { 2567 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", 2568 "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_image", 2569 "VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain", 2570 "VK_LAYER_GOOGLE_unique_objects" 2571 }; 2572 2573 /* Look for validation layers */ 2574 VkBool32 validation_found = 0; 2575 if (demo->validate) { 2576 2577 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL); 2578 assert(!err); 2579 2580 instance_validation_layers = instance_validation_layers_alt1; 2581 if (instance_layer_count > 0) { 2582 VkLayerProperties *instance_layers = 2583 malloc(sizeof (VkLayerProperties) * instance_layer_count); 2584 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, 2585 instance_layers); 2586 assert(!err); 2587 2588 2589 validation_found = demo_check_layers( 2590 ARRAY_SIZE(instance_validation_layers_alt1), 2591 instance_validation_layers, instance_layer_count, 2592 instance_layers); 2593 if (validation_found) { 2594 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1); 2595 demo->enabled_layers[0] = "VK_LAYER_LUNARG_standard_validation"; 2596 validation_layer_count = 1; 2597 } else { 2598 // use alternative set of validation layers 2599 instance_validation_layers = instance_validation_layers_alt2; 2600 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2); 2601 validation_found = demo_check_layers( 2602 ARRAY_SIZE(instance_validation_layers_alt2), 2603 instance_validation_layers, instance_layer_count, 2604 instance_layers); 2605 validation_layer_count = 2606 ARRAY_SIZE(instance_validation_layers_alt2); 2607 for (uint32_t i = 0; i < validation_layer_count; i++) { 2608 demo->enabled_layers[i] = instance_validation_layers[i]; 2609 } 2610 } 2611 free(instance_layers); 2612 } 2613 2614 if (!validation_found) { 2615 ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find " 2616 "required validation layer.\n\n" 2617 "Please look at the Getting Started guide for additional " 2618 "information.\n", 2619 "vkCreateInstance Failure"); 2620 } 2621 } 2622 2623 /* Look for instance extensions */ 2624 VkBool32 surfaceExtFound = 0; 2625 VkBool32 platformSurfaceExtFound = 0; 2626#if defined(VK_USE_PLATFORM_XLIB_KHR) 2627 VkBool32 xlibSurfaceExtFound = 0; 2628#endif 2629 memset(demo->extension_names, 0, sizeof(demo->extension_names)); 2630 2631 err = vkEnumerateInstanceExtensionProperties( 2632 NULL, &instance_extension_count, NULL); 2633 assert(!err); 2634 2635 if (instance_extension_count > 0) { 2636 VkExtensionProperties *instance_extensions = 2637 malloc(sizeof(VkExtensionProperties) * instance_extension_count); 2638 err = vkEnumerateInstanceExtensionProperties( 2639 NULL, &instance_extension_count, instance_extensions); 2640 assert(!err); 2641 for (uint32_t i = 0; i < instance_extension_count; i++) { 2642 if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME, 2643 instance_extensions[i].extensionName)) { 2644 surfaceExtFound = 1; 2645 demo->extension_names[demo->enabled_extension_count++] = 2646 VK_KHR_SURFACE_EXTENSION_NAME; 2647 } 2648#if defined(VK_USE_PLATFORM_WIN32_KHR) 2649 if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, 2650 instance_extensions[i].extensionName)) { 2651 platformSurfaceExtFound = 1; 2652 demo->extension_names[demo->enabled_extension_count++] = 2653 VK_KHR_WIN32_SURFACE_EXTENSION_NAME; 2654 } 2655#endif 2656#if defined(VK_USE_PLATFORM_XLIB_KHR) 2657 if (!strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, 2658 instance_extensions[i].extensionName)) { 2659 platformSurfaceExtFound = 1; 2660 xlibSurfaceExtFound = 1; 2661 demo->extension_names[demo->enabled_extension_count++] = 2662 VK_KHR_XLIB_SURFACE_EXTENSION_NAME; 2663 } 2664#endif 2665#if defined(VK_USE_PLATFORM_XCB_KHR) 2666 if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME, 2667 instance_extensions[i].extensionName)) { 2668 platformSurfaceExtFound = 1; 2669 demo->extension_names[demo->enabled_extension_count++] = 2670 VK_KHR_XCB_SURFACE_EXTENSION_NAME; 2671 } 2672#endif 2673#if defined(VK_USE_PLATFORM_WAYLAND_KHR) 2674 if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, 2675 instance_extensions[i].extensionName)) { 2676 platformSurfaceExtFound = 1; 2677 demo->extension_names[demo->enabled_extension_count++] = 2678 VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME; 2679 } 2680#endif 2681#if defined(VK_USE_PLATFORM_ANDROID_KHR) 2682 if (!strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, 2683 instance_extensions[i].extensionName)) { 2684 platformSurfaceExtFound = 1; 2685 demo->extension_names[demo->enabled_extension_count++] = 2686 VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; 2687 } 2688#endif 2689 if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, 2690 instance_extensions[i].extensionName)) { 2691 if (demo->validate) { 2692 demo->extension_names[demo->enabled_extension_count++] = 2693 VK_EXT_DEBUG_REPORT_EXTENSION_NAME; 2694 } 2695 } 2696 assert(demo->enabled_extension_count < 64); 2697 } 2698 2699 free(instance_extensions); 2700 } 2701 2702 if (!surfaceExtFound) { 2703 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find " 2704 "the " VK_KHR_SURFACE_EXTENSION_NAME 2705 " extension.\n\nDo you have a compatible " 2706 "Vulkan installable client driver (ICD) installed?\nPlease " 2707 "look at the Getting Started guide for additional " 2708 "information.\n", 2709 "vkCreateInstance Failure"); 2710 } 2711 if (!platformSurfaceExtFound) { 2712#if defined(VK_USE_PLATFORM_WIN32_KHR) 2713 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find " 2714 "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME 2715 " extension.\n\nDo you have a compatible " 2716 "Vulkan installable client driver (ICD) installed?\nPlease " 2717 "look at the Getting Started guide for additional " 2718 "information.\n", 2719 "vkCreateInstance Failure"); 2720#elif defined(VK_USE_PLATFORM_XCB_KHR) 2721 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find " 2722 "the " VK_KHR_XCB_SURFACE_EXTENSION_NAME 2723 " extension.\n\nDo you have a compatible " 2724 "Vulkan installable client driver (ICD) installed?\nPlease " 2725 "look at the Getting Started guide for additional " 2726 "information.\n", 2727 "vkCreateInstance Failure"); 2728#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) 2729 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find " 2730 "the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME 2731 " extension.\n\nDo you have a compatible " 2732 "Vulkan installable client driver (ICD) installed?\nPlease " 2733 "look at the Getting Started guide for additional " 2734 "information.\n", 2735 "vkCreateInstance Failure"); 2736#elif defined(VK_USE_PLATFORM_ANDROID_KHR) 2737 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find " 2738 "the " VK_KHR_ANDROID_SURFACE_EXTENSION_NAME 2739 " extension.\n\nDo you have a compatible " 2740 "Vulkan installable client driver (ICD) installed?\nPlease " 2741 "look at the Getting Started guide for additional " 2742 "information.\n", 2743 "vkCreateInstance Failure"); 2744#endif 2745 } 2746#if defined(VK_USE_PLATFORM_XLIB_KHR) 2747 if (demo->use_xlib && !xlibSurfaceExtFound) { 2748 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find " 2749 "the " VK_KHR_XLIB_SURFACE_EXTENSION_NAME 2750 " extension.\n\nDo you have a compatible " 2751 "Vulkan installable client driver (ICD) installed?\nPlease " 2752 "look at the Getting Started guide for additional " 2753 "information.\n", 2754 "vkCreateInstance Failure"); 2755 } 2756#endif 2757 const VkApplicationInfo app = { 2758 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 2759 .pNext = NULL, 2760 .pApplicationName = APP_SHORT_NAME, 2761 .applicationVersion = 0, 2762 .pEngineName = APP_SHORT_NAME, 2763 .engineVersion = 0, 2764 .apiVersion = VK_API_VERSION_1_0, 2765 }; 2766 VkInstanceCreateInfo inst_info = { 2767 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 2768 .pNext = NULL, 2769 .pApplicationInfo = &app, 2770 .enabledLayerCount = demo->enabled_layer_count, 2771 .ppEnabledLayerNames = (const char *const *)instance_validation_layers, 2772 .enabledExtensionCount = demo->enabled_extension_count, 2773 .ppEnabledExtensionNames = (const char *const *)demo->extension_names, 2774 }; 2775 2776 /* 2777 * This is info for a temp callback to use during CreateInstance. 2778 * After the instance is created, we use the instance-based 2779 * function to register the final callback. 2780 */ 2781 VkDebugReportCallbackCreateInfoEXT dbgCreateInfo; 2782 if (demo->validate) { 2783 dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; 2784 dbgCreateInfo.pNext = NULL; 2785 dbgCreateInfo.pfnCallback = demo->use_break ? BreakCallback : dbgFunc; 2786 dbgCreateInfo.pUserData = demo; 2787 dbgCreateInfo.flags = 2788 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; 2789 inst_info.pNext = &dbgCreateInfo; 2790 } 2791 2792 uint32_t gpu_count; 2793 2794 err = vkCreateInstance(&inst_info, NULL, &demo->inst); 2795 if (err == VK_ERROR_INCOMPATIBLE_DRIVER) { 2796 ERR_EXIT("Cannot find a compatible Vulkan installable client driver " 2797 "(ICD).\n\nPlease look at the Getting Started guide for " 2798 "additional information.\n", 2799 "vkCreateInstance Failure"); 2800 } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) { 2801 ERR_EXIT("Cannot find a specified extension library" 2802 ".\nMake sure your layers path is set appropriately.\n", 2803 "vkCreateInstance Failure"); 2804 } else if (err) { 2805 ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan " 2806 "installable client driver (ICD) installed?\nPlease look at " 2807 "the Getting Started guide for additional information.\n", 2808 "vkCreateInstance Failure"); 2809 } 2810 2811 /* Make initial call to query gpu_count, then second call for gpu info*/ 2812 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL); 2813 assert(!err && gpu_count > 0); 2814 2815 if (gpu_count > 0) { 2816 VkPhysicalDevice *physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count); 2817 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, physical_devices); 2818 assert(!err); 2819 /* For cube demo we just grab the first physical device */ 2820 demo->gpu = physical_devices[0]; 2821 free(physical_devices); 2822 } else { 2823 ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible devices.\n\n" 2824 "Do you have a compatible Vulkan installable client driver (ICD) " 2825 "installed?\nPlease look at the Getting Started guide for " 2826 "additional information.\n", 2827 "vkEnumeratePhysicalDevices Failure"); 2828 } 2829 2830 /* Look for device extensions */ 2831 uint32_t device_extension_count = 0; 2832 VkBool32 swapchainExtFound = 0; 2833 demo->enabled_extension_count = 0; 2834 memset(demo->extension_names, 0, sizeof(demo->extension_names)); 2835 2836 err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL, 2837 &device_extension_count, NULL); 2838 assert(!err); 2839 2840 if (device_extension_count > 0) { 2841 VkExtensionProperties *device_extensions = 2842 malloc(sizeof(VkExtensionProperties) * device_extension_count); 2843 err = vkEnumerateDeviceExtensionProperties( 2844 demo->gpu, NULL, &device_extension_count, device_extensions); 2845 assert(!err); 2846 2847 for (uint32_t i = 0; i < device_extension_count; i++) { 2848 if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 2849 device_extensions[i].extensionName)) { 2850 swapchainExtFound = 1; 2851 demo->extension_names[demo->enabled_extension_count++] = 2852 VK_KHR_SWAPCHAIN_EXTENSION_NAME; 2853 } 2854 assert(demo->enabled_extension_count < 64); 2855 } 2856 2857 free(device_extensions); 2858 } 2859 2860 if (!swapchainExtFound) { 2861 ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find " 2862 "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME 2863 " extension.\n\nDo you have a compatible " 2864 "Vulkan installable client driver (ICD) installed?\nPlease " 2865 "look at the Getting Started guide for additional " 2866 "information.\n", 2867 "vkCreateInstance Failure"); 2868 } 2869 2870 if (demo->validate) { 2871 demo->CreateDebugReportCallback = 2872 (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr( 2873 demo->inst, "vkCreateDebugReportCallbackEXT"); 2874 demo->DestroyDebugReportCallback = 2875 (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr( 2876 demo->inst, "vkDestroyDebugReportCallbackEXT"); 2877 if (!demo->CreateDebugReportCallback) { 2878 ERR_EXIT( 2879 "GetProcAddr: Unable to find vkCreateDebugReportCallbackEXT\n", 2880 "vkGetProcAddr Failure"); 2881 } 2882 if (!demo->DestroyDebugReportCallback) { 2883 ERR_EXIT( 2884 "GetProcAddr: Unable to find vkDestroyDebugReportCallbackEXT\n", 2885 "vkGetProcAddr Failure"); 2886 } 2887 demo->DebugReportMessage = 2888 (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr( 2889 demo->inst, "vkDebugReportMessageEXT"); 2890 if (!demo->DebugReportMessage) { 2891 ERR_EXIT("GetProcAddr: Unable to find vkDebugReportMessageEXT\n", 2892 "vkGetProcAddr Failure"); 2893 } 2894 2895 VkDebugReportCallbackCreateInfoEXT dbgCreateInfo; 2896 PFN_vkDebugReportCallbackEXT callback; 2897 callback = demo->use_break ? BreakCallback : dbgFunc; 2898 dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; 2899 dbgCreateInfo.pNext = NULL; 2900 dbgCreateInfo.pfnCallback = callback; 2901 dbgCreateInfo.pUserData = demo; 2902 dbgCreateInfo.flags = 2903 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; 2904 err = demo->CreateDebugReportCallback(demo->inst, &dbgCreateInfo, NULL, 2905 &demo->msg_callback); 2906 switch (err) { 2907 case VK_SUCCESS: 2908 break; 2909 case VK_ERROR_OUT_OF_HOST_MEMORY: 2910 ERR_EXIT("CreateDebugReportCallback: out of host memory\n", 2911 "CreateDebugReportCallback Failure"); 2912 break; 2913 default: 2914 ERR_EXIT("CreateDebugReportCallback: unknown failure\n", 2915 "CreateDebugReportCallback Failure"); 2916 break; 2917 } 2918 } 2919 vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props); 2920 2921 /* Call with NULL data to get count */ 2922 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, 2923 &demo->queue_family_count, NULL); 2924 assert(demo->queue_family_count >= 1); 2925 2926 demo->queue_props = (VkQueueFamilyProperties *)malloc( 2927 demo->queue_family_count * sizeof(VkQueueFamilyProperties)); 2928 vkGetPhysicalDeviceQueueFamilyProperties( 2929 demo->gpu, &demo->queue_family_count, demo->queue_props); 2930 2931 // Query fine-grained feature support for this device. 2932 // If app has specific feature requirements it should check supported 2933 // features based on this query 2934 VkPhysicalDeviceFeatures physDevFeatures; 2935 vkGetPhysicalDeviceFeatures(demo->gpu, &physDevFeatures); 2936 2937 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR); 2938 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceCapabilitiesKHR); 2939 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR); 2940 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR); 2941 GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR); 2942} 2943 2944static void demo_create_device(struct demo *demo) { 2945 VkResult U_ASSERT_ONLY err; 2946 float queue_priorities[1] = {0.0}; 2947 VkDeviceQueueCreateInfo queues[2]; 2948 queues[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 2949 queues[0].pNext = NULL; 2950 queues[0].queueFamilyIndex = demo->graphics_queue_family_index; 2951 queues[0].queueCount = 1; 2952 queues[0].pQueuePriorities = queue_priorities; 2953 queues[0].flags = 0; 2954 2955 VkDeviceCreateInfo device = { 2956 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 2957 .pNext = NULL, 2958 .queueCreateInfoCount = 1, 2959 .pQueueCreateInfos = queues, 2960 .enabledLayerCount = 0, 2961 .ppEnabledLayerNames = NULL, 2962 .enabledExtensionCount = demo->enabled_extension_count, 2963 .ppEnabledExtensionNames = (const char *const *)demo->extension_names, 2964 .pEnabledFeatures = 2965 NULL, // If specific features are required, pass them in here 2966 }; 2967 if (demo->separate_present_queue) { 2968 queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 2969 queues[1].pNext = NULL; 2970 queues[1].queueFamilyIndex = demo->present_queue_family_index; 2971 queues[1].queueCount = 1; 2972 queues[1].pQueuePriorities = queue_priorities; 2973 queues[1].flags = 0; 2974 device.queueCreateInfoCount = 2; 2975 } 2976 err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device); 2977 assert(!err); 2978} 2979 2980static void demo_init_vk_swapchain(struct demo *demo) { 2981 VkResult U_ASSERT_ONLY err; 2982 uint32_t i; 2983 2984// Create a WSI surface for the window: 2985#if defined(VK_USE_PLATFORM_WIN32_KHR) 2986 VkWin32SurfaceCreateInfoKHR createInfo; 2987 createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; 2988 createInfo.pNext = NULL; 2989 createInfo.flags = 0; 2990 createInfo.hinstance = demo->connection; 2991 createInfo.hwnd = demo->window; 2992 2993 err = 2994 vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface); 2995#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) && !defined(VK_USE_PLATFORM_XCB_KHR) 2996 VkWaylandSurfaceCreateInfoKHR createInfo; 2997 createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; 2998 createInfo.pNext = NULL; 2999 createInfo.flags = 0; 3000 createInfo.display = demo->display; 3001 createInfo.surface = demo->window; 3002 3003 err = vkCreateWaylandSurfaceKHR(demo->inst, &createInfo, NULL, 3004 &demo->surface); 3005#elif defined(VK_USE_PLATFORM_ANDROID_KHR) 3006 VkAndroidSurfaceCreateInfoKHR createInfo; 3007 createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; 3008 createInfo.pNext = NULL; 3009 createInfo.flags = 0; 3010 createInfo.window = (ANativeWindow*)(demo->window); 3011 3012 err = vkCreateAndroidSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface); 3013#endif 3014 if (demo->use_xlib) { 3015#if defined(VK_USE_PLATFORM_XLIB_KHR) 3016 VkXlibSurfaceCreateInfoKHR createInfo; 3017 createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; 3018 createInfo.pNext = NULL; 3019 createInfo.flags = 0; 3020 createInfo.dpy = demo->display; 3021 createInfo.window = demo->xlib_window; 3022 3023 err = vkCreateXlibSurfaceKHR(demo->inst, &createInfo, NULL, 3024 &demo->surface); 3025#endif 3026 } 3027 else { 3028#if defined(VK_USE_PLATFORM_XCB_KHR) 3029 VkXcbSurfaceCreateInfoKHR createInfo; 3030 createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; 3031 createInfo.pNext = NULL; 3032 createInfo.flags = 0; 3033 createInfo.connection = demo->connection; 3034 createInfo.window = demo->xcb_window; 3035 3036 err = vkCreateXcbSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface); 3037#endif 3038 } 3039 assert(!err); 3040 3041 // Iterate over each queue to learn whether it supports presenting: 3042 VkBool32 *supportsPresent = 3043 (VkBool32 *)malloc(demo->queue_family_count * sizeof(VkBool32)); 3044 for (i = 0; i < demo->queue_family_count; i++) { 3045 demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface, 3046 &supportsPresent[i]); 3047 } 3048 3049 // Search for a graphics and a present queue in the array of queue 3050 // families, try to find one that supports both 3051 uint32_t graphicsQueueFamilyIndex = UINT32_MAX; 3052 uint32_t presentQueueFamilyIndex = UINT32_MAX; 3053 for (i = 0; i < demo->queue_family_count; i++) { 3054 if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { 3055 if (graphicsQueueFamilyIndex == UINT32_MAX) { 3056 graphicsQueueFamilyIndex = i; 3057 } 3058 3059 if (supportsPresent[i] == VK_TRUE) { 3060 graphicsQueueFamilyIndex = i; 3061 presentQueueFamilyIndex = i; 3062 break; 3063 } 3064 } 3065 } 3066 3067 if (presentQueueFamilyIndex == UINT32_MAX) { 3068 // If didn't find a queue that supports both graphics and present, then 3069 // find a separate present queue. 3070 for (i = 0; i < demo->queue_family_count; ++i) { 3071 if (supportsPresent[i] == VK_TRUE) { 3072 presentQueueFamilyIndex = i; 3073 break; 3074 } 3075 } 3076 } 3077 3078 // Generate error if could not find both a graphics and a present queue 3079 if (graphicsQueueFamilyIndex == UINT32_MAX || 3080 presentQueueFamilyIndex == UINT32_MAX) { 3081 ERR_EXIT("Could not find both graphics and present queues\n", 3082 "Swapchain Initialization Failure"); 3083 } 3084 3085 demo->graphics_queue_family_index = graphicsQueueFamilyIndex; 3086 demo->present_queue_family_index = presentQueueFamilyIndex; 3087 demo->separate_present_queue = 3088 (demo->graphics_queue_family_index != demo->present_queue_family_index); 3089 free(supportsPresent); 3090 3091 demo_create_device(demo); 3092 3093 GET_DEVICE_PROC_ADDR(demo->device, CreateSwapchainKHR); 3094 GET_DEVICE_PROC_ADDR(demo->device, DestroySwapchainKHR); 3095 GET_DEVICE_PROC_ADDR(demo->device, GetSwapchainImagesKHR); 3096 GET_DEVICE_PROC_ADDR(demo->device, AcquireNextImageKHR); 3097 GET_DEVICE_PROC_ADDR(demo->device, QueuePresentKHR); 3098 3099 vkGetDeviceQueue(demo->device, demo->graphics_queue_family_index, 0, 3100 &demo->graphics_queue); 3101 3102 if (!demo->separate_present_queue) { 3103 demo->present_queue = demo->graphics_queue; 3104 } else { 3105 vkGetDeviceQueue(demo->device, demo->present_queue_family_index, 0, 3106 &demo->present_queue); 3107 } 3108 3109 // Get the list of VkFormat's that are supported: 3110 uint32_t formatCount; 3111 err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface, 3112 &formatCount, NULL); 3113 assert(!err); 3114 VkSurfaceFormatKHR *surfFormats = 3115 (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); 3116 err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface, 3117 &formatCount, surfFormats); 3118 assert(!err); 3119 // If the format list includes just one entry of VK_FORMAT_UNDEFINED, 3120 // the surface has no preferred format. Otherwise, at least one 3121 // supported format will be returned. 3122 if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) { 3123 demo->format = VK_FORMAT_B8G8R8A8_UNORM; 3124 } else { 3125 assert(formatCount >= 1); 3126 demo->format = surfFormats[0].format; 3127 } 3128 demo->color_space = surfFormats[0].colorSpace; 3129 3130 demo->quit = false; 3131 demo->curFrame = 0; 3132 3133 // Create semaphores to synchronize acquiring presentable buffers before 3134 // rendering and waiting for drawing to be complete before presenting 3135 VkSemaphoreCreateInfo semaphoreCreateInfo = { 3136 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 3137 .pNext = NULL, 3138 .flags = 0, 3139 }; 3140 3141 // Create fences that we can use to throttle if we get too far 3142 // ahead of the image presents 3143 VkFenceCreateInfo fence_ci = { 3144 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 3145 .pNext = NULL, 3146 .flags = VK_FENCE_CREATE_SIGNALED_BIT 3147 }; 3148 for (uint32_t i = 0; i < FRAME_LAG; i++) { 3149 vkCreateFence(demo->device, &fence_ci, NULL, &demo->fences[i]); 3150 err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL, 3151 &demo->image_acquired_semaphores[i]); 3152 assert(!err); 3153 3154 err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL, 3155 &demo->draw_complete_semaphores[i]); 3156 assert(!err); 3157 3158 if (demo->separate_present_queue) { 3159 err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL, 3160 &demo->image_ownership_semaphores[i]); 3161 assert(!err); 3162 } 3163 } 3164 demo->frame_index = 0; 3165 3166 // Get Memory information and properties 3167 vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties); 3168} 3169 3170#if defined(VK_USE_PLATFORM_WAYLAND_KHR) && !defined(VK_USE_PLATFORM_XCB_KHR) 3171static void registry_handle_global(void *data, struct wl_registry *registry, 3172 uint32_t name, const char *interface, 3173 uint32_t version UNUSED) { 3174 struct demo *demo = data; 3175 if (strcmp(interface, "wl_compositor") == 0) { 3176 demo->compositor = 3177 wl_registry_bind(registry, name, &wl_compositor_interface, 3); 3178 /* Todo: When xdg_shell protocol has stablized, we should move wl_shell 3179 * tp xdg_shell */ 3180 } else if (strcmp(interface, "wl_shell") == 0) { 3181 demo->shell = wl_registry_bind(registry, name, &wl_shell_interface, 1); 3182 } 3183} 3184 3185static void registry_handle_global_remove(void *data UNUSED, 3186 struct wl_registry *registry UNUSED, 3187 uint32_t name UNUSED) {} 3188 3189static const struct wl_registry_listener registry_listener = { 3190 registry_handle_global, registry_handle_global_remove}; 3191#endif 3192 3193static void demo_init_connection(struct demo *demo) { 3194#if defined(VK_USE_PLATFORM_XCB_KHR) 3195 const xcb_setup_t *setup; 3196 xcb_screen_iterator_t iter; 3197 int scr; 3198 3199 demo->connection = xcb_connect(NULL, &scr); 3200 if (xcb_connection_has_error(demo->connection) > 0) { 3201 printf("Cannot find a compatible Vulkan installable client driver " 3202 "(ICD).\nExiting ...\n"); 3203 fflush(stdout); 3204 exit(1); 3205 } 3206 3207 setup = xcb_get_setup(demo->connection); 3208 iter = xcb_setup_roots_iterator(setup); 3209 while (scr-- > 0) 3210 xcb_screen_next(&iter); 3211 3212 demo->screen = iter.data; 3213#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) 3214 demo->display = wl_display_connect(NULL); 3215 3216 if (demo->display == NULL) { 3217 printf("Cannot find a compatible Vulkan installable client driver " 3218 "(ICD).\nExiting ...\n"); 3219 fflush(stdout); 3220 exit(1); 3221 } 3222 3223 demo->registry = wl_display_get_registry(demo->display); 3224 wl_registry_add_listener(demo->registry, ®istry_listener, demo); 3225 wl_display_dispatch(demo->display); 3226#endif 3227} 3228 3229static void demo_init(struct demo *demo, int argc, char **argv) { 3230 vec3 eye = {0.0f, 3.0f, 5.0f}; 3231 vec3 origin = {0, 0, 0}; 3232 vec3 up = {0.0f, 1.0f, 0.0}; 3233 3234 memset(demo, 0, sizeof(*demo)); 3235 demo->frameCount = INT32_MAX; 3236 3237 for (int i = 1; i < argc; i++) { 3238 if (strcmp(argv[i], "--use_staging") == 0) { 3239 demo->use_staging_buffer = true; 3240 continue; 3241 } 3242 if (strcmp(argv[i], "--break") == 0) { 3243 demo->use_break = true; 3244 continue; 3245 } 3246 if (strcmp(argv[i], "--validate") == 0) { 3247 demo->validate = true; 3248 continue; 3249 } 3250#if defined(VK_USE_PLATFORM_XLIB_KHR) 3251 if (strcmp(argv[i], "--xlib") == 0) { 3252 demo->use_xlib = true; 3253 continue; 3254 } 3255#endif 3256 if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX && 3257 i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 && 3258 demo->frameCount >= 0) { 3259 i++; 3260 continue; 3261 } 3262 if (strcmp(argv[i], "--suppress_popups") == 0) { 3263 demo->suppress_popups = true; 3264 continue; 3265 } 3266 3267#if defined(ANDROID) 3268 ERR_EXIT("Usage: cube [--validate]\n", "Usage"); 3269#else 3270 fprintf(stderr, "Usage:\n %s [--use_staging] [--validate] [--break] " 3271#if defined(VK_USE_PLATFORM_XLIB_KHR) 3272 "[--xlib] " 3273#endif 3274 "[--c <framecount>] [--suppress_popups]\n", 3275 APP_SHORT_NAME); 3276 fflush(stderr); 3277 exit(1); 3278#endif 3279 } 3280 3281 if (!demo->use_xlib) 3282 demo_init_connection(demo); 3283 3284 demo_init_vk(demo); 3285 3286 demo->width = 500; 3287 demo->height = 500; 3288 3289 demo->spin_angle = 4.0f; 3290 demo->spin_increment = 0.2f; 3291 demo->pause = false; 3292 3293 mat4x4_perspective(demo->projection_matrix, (float)degreesToRadians(45.0f), 3294 1.0f, 0.1f, 100.0f); 3295 mat4x4_look_at(demo->view_matrix, eye, origin, up); 3296 mat4x4_identity(demo->model_matrix); 3297 3298 demo->projection_matrix[1][1]*=-1; //Flip projection matrix from GL to Vulkan orientation. 3299} 3300 3301#if defined(VK_USE_PLATFORM_WIN32_KHR) 3302// Include header required for parsing the command line options. 3303#include <shellapi.h> 3304 3305int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, 3306 int nCmdShow) { 3307 MSG msg; // message 3308 bool done; // flag saying when app is complete 3309 int argc; 3310 char **argv; 3311 3312 // Use the CommandLine functions to get the command line arguments. 3313 // Unfortunately, Microsoft outputs 3314 // this information as wide characters for Unicode, and we simply want the 3315 // Ascii version to be compatible 3316 // with the non-Windows side. So, we have to convert the information to 3317 // Ascii character strings. 3318 LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc); 3319 if (NULL == commandLineArgs) { 3320 argc = 0; 3321 } 3322 3323 if (argc > 0) { 3324 argv = (char **)malloc(sizeof(char *) * argc); 3325 if (argv == NULL) { 3326 argc = 0; 3327 } else { 3328 for (int iii = 0; iii < argc; iii++) { 3329 size_t wideCharLen = wcslen(commandLineArgs[iii]); 3330 size_t numConverted = 0; 3331 3332 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1)); 3333 if (argv[iii] != NULL) { 3334 wcstombs_s(&numConverted, argv[iii], wideCharLen + 1, 3335 commandLineArgs[iii], wideCharLen + 1); 3336 } 3337 } 3338 } 3339 } else { 3340 argv = NULL; 3341 } 3342 3343 demo_init(&demo, argc, argv); 3344 3345 // Free up the items we had to allocate for the command line arguments. 3346 if (argc > 0 && argv != NULL) { 3347 for (int iii = 0; iii < argc; iii++) { 3348 if (argv[iii] != NULL) { 3349 free(argv[iii]); 3350 } 3351 } 3352 free(argv); 3353 } 3354 3355 demo.connection = hInstance; 3356 strncpy(demo.name, "cube", APP_NAME_STR_LEN); 3357 demo_create_window(&demo); 3358 demo_init_vk_swapchain(&demo); 3359 3360 demo_prepare(&demo); 3361 3362 done = false; // initialize loop condition variable 3363 3364 // main message loop 3365 while (!done) { 3366 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); 3367 if (msg.message == WM_QUIT) // check for a quit message 3368 { 3369 done = true; // if found, quit app 3370 } else { 3371 /* Translate and dispatch to event queue*/ 3372 TranslateMessage(&msg); 3373 DispatchMessage(&msg); 3374 } 3375 RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT); 3376 } 3377 3378 demo_cleanup(&demo); 3379 3380 return (int)msg.wParam; 3381} 3382#elif defined(VK_USE_PLATFORM_ANDROID_KHR) 3383#include <android/log.h> 3384#include <android_native_app_glue.h> 3385#include "android_util.h" 3386 3387static bool initialized = false; 3388static bool active = false; 3389struct demo demo; 3390 3391static int32_t processInput(struct android_app* app, AInputEvent* event) { 3392 return 0; 3393} 3394 3395static void processCommand(struct android_app* app, int32_t cmd) { 3396 switch(cmd) { 3397 case APP_CMD_INIT_WINDOW: { 3398 if (app->window) { 3399 // We're getting a new window. If the app is starting up, we 3400 // need to initialize. If the app has already been 3401 // initialized, that means that we lost our previous window, 3402 // which means that we have a lot of work to do. At a minimum, 3403 // we need to destroy the swapchain and surface associated with 3404 // the old window, and create a new surface and swapchain. 3405 // However, since there are a lot of other objects/state that 3406 // is tied to the swapchain, it's easiest to simply cleanup and 3407 // start over (i.e. use a brute-force approach of re-starting 3408 // the app) 3409 if (demo.prepared) { 3410 demo_cleanup(&demo); 3411 } 3412 3413 // Parse Intents into argc, argv 3414 // Use the following key to send arguments, i.e. 3415 // --es args "--validate" 3416 const char key[] = "args"; 3417 char* appTag = (char*) APP_SHORT_NAME; 3418 int argc = 0; 3419 char** argv = get_args(app, key, appTag, &argc); 3420 3421 __android_log_print(ANDROID_LOG_INFO, appTag, "argc = %i", argc); 3422 for (int i = 0; i < argc; i++) 3423 __android_log_print(ANDROID_LOG_INFO, appTag, "argv[%i] = %s", i, argv[i]); 3424 3425 demo_init(&demo, argc, argv); 3426 3427 // Free the argv malloc'd by get_args 3428 for (int i = 0; i < argc; i++) 3429 free(argv[i]); 3430 3431 demo.window = (void*)app->window; 3432 demo_init_vk_swapchain(&demo); 3433 demo_prepare(&demo); 3434 initialized = true; 3435 } 3436 break; 3437 } 3438 case APP_CMD_GAINED_FOCUS: { 3439 active = true; 3440 break; 3441 } 3442 case APP_CMD_LOST_FOCUS: { 3443 active = false; 3444 break; 3445 } 3446 } 3447} 3448 3449void android_main(struct android_app *app) 3450{ 3451 app_dummy(); 3452 3453#ifdef ANDROID 3454 int vulkanSupport = InitVulkan(); 3455 if (vulkanSupport == 0) 3456 return; 3457#endif 3458 3459 demo.prepared = false; 3460 3461 app->onAppCmd = processCommand; 3462 app->onInputEvent = processInput; 3463 3464 while(1) { 3465 int events; 3466 struct android_poll_source* source; 3467 while (ALooper_pollAll(active ? 0 : -1, NULL, &events, (void**)&source) >= 0) { 3468 if (source) { 3469 source->process(app, source); 3470 } 3471 3472 if (app->destroyRequested != 0) { 3473 demo_cleanup(&demo); 3474 return; 3475 } 3476 } 3477 if (initialized && active) { 3478 demo_run(&demo); 3479 } 3480 } 3481 3482} 3483#else 3484int main(int argc, char **argv) { 3485 struct demo demo; 3486 3487 demo_init(&demo, argc, argv); 3488#if defined(VK_USE_PLATFORM_XLIB_KHR) && defined(VK_USE_PLATFORM_XCB_KHR) 3489 if (demo.use_xlib) 3490 demo_create_xlib_window(&demo); 3491 else 3492 demo_create_xcb_window(&demo); 3493#elif defined(VK_USE_PLATFORM_XCB_KHR) 3494 demo_create_xcb_window(&demo); 3495#elif defined(VK_USE_PLATFORM_XLIB_KHR) 3496 demo_create_xlib_window(&demo); 3497#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) 3498 demo_create_window(&demo); 3499#endif 3500 3501 demo_init_vk_swapchain(&demo); 3502 3503 demo_prepare(&demo); 3504 3505#if defined(VK_USE_PLATFORM_XLIB_KHR) && defined(VK_USE_PLATFORM_XCB_KHR) 3506 if (demo.use_xlib) 3507 demo_run_xlib(&demo); 3508 else 3509 demo_run_xcb(&demo); 3510#elif defined(VK_USE_PLATFORM_XCB_KHR) 3511 demo_run_xcb(&demo); 3512#elif defined(VK_USE_PLATFORM_XLIB_KHR) 3513 demo_run_xlib(&demo); 3514#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) 3515 demo_run(&demo); 3516#endif 3517 3518 demo_cleanup(&demo); 3519 3520 return validation_error; 3521} 3522#endif 3523