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