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