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