tri.c revision 85180252441dad59e6967261a0a744af29e87968
1/* 2 * Vulkan 3 * 4 * Copyright (C) 2014-2015 LunarG, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24/* 25 * Draw a textured triangle with depth testing. This is written against Intel 26 * ICD. It does not do state transition nor object memory binding like it 27 * should. It also does no error checking. 28 */ 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include <stdbool.h> 34#include <assert.h> 35 36#ifdef _WIN32 37#pragma comment(linker, "/subsystem:windows") 38#include <windows.h> 39#define APP_NAME_STR_LEN 80 40#else // _WIN32 41#include <xcb/xcb.h> 42#endif // _WIN32 43 44#include <vulkan.h> 45#include "vk_debug_report_lunarg.h" 46#include <vk_ext_khr_swapchain.h> 47#include <vk_ext_khr_device_swapchain.h> 48 49#include "icd-spv.h" 50 51#define DEMO_TEXTURE_COUNT 1 52#define VERTEX_BUFFER_BIND_ID 0 53#define APP_SHORT_NAME "tri" 54#define APP_LONG_NAME "The Vulkan Triangle Demo Program" 55 56#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 57 58#if defined(NDEBUG) && defined(__GNUC__) 59#define U_ASSERT_ONLY __attribute__((unused)) 60#else 61#define U_ASSERT_ONLY 62#endif 63 64#ifdef _WIN32 65#define ERR_EXIT(err_msg, err_class) \ 66 do { \ 67 MessageBox(NULL, err_msg, err_class, MB_OK); \ 68 exit(1); \ 69 } while (0) 70#else // _WIN32 71 72#define ERR_EXIT(err_msg, err_class) \ 73 do { \ 74 printf(err_msg); \ 75 fflush(stdout); \ 76 exit(1); \ 77 } while (0) 78#endif // _WIN32 79 80#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \ 81{ \ 82 demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetInstanceProcAddr(inst, "vk"#entrypoint); \ 83 if (demo->fp##entrypoint == NULL) { \ 84 ERR_EXIT("vkGetInstanceProcAddr failed to find vk"#entrypoint, \ 85 "vkGetInstanceProcAddr Failure"); \ 86 } \ 87} 88 89#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \ 90{ \ 91 demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetDeviceProcAddr(dev, "vk"#entrypoint); \ 92 if (demo->fp##entrypoint == NULL) { \ 93 ERR_EXIT("vkGetDeviceProcAddr failed to find vk"#entrypoint, \ 94 "vkGetDeviceProcAddr Failure"); \ 95 } \ 96} 97 98struct texture_object { 99 VkSampler sampler; 100 101 VkImage image; 102 VkImageLayout imageLayout; 103 104 VkDeviceMemory mem; 105 VkImageView view; 106 int32_t tex_width, tex_height; 107}; 108 109VkBool32 dbgFunc( 110 VkFlags msgFlags, 111 VkDbgObjectType objType, 112 uint64_t srcObject, 113 size_t location, 114 int32_t msgCode, 115 const char* pLayerPrefix, 116 const char* pMsg, 117 void* pUserData) 118{ 119 char *message = (char *) malloc(strlen(pMsg)+100); 120 121 assert (message); 122 123 if (msgFlags & VK_DBG_REPORT_ERROR_BIT) { 124 sprintf(message,"ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 125 } else if (msgFlags & VK_DBG_REPORT_WARN_BIT) { 126 sprintf(message,"WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 127 } else { 128 return false; 129 } 130 131#ifdef _WIN32 132 MessageBox(NULL, message, "Alert", MB_OK); 133#else 134 printf("%s\n",message); 135 fflush(stdout); 136#endif 137 free(message); 138 139 /* 140 * false indicates that layer should not bail-out of an 141 * API call that had validation failures. This may mean that the 142 * app dies inside the driver due to invalid parameter(s). 143 * That's what would happen without validation layers, so we'll 144 * keep that behavior here. 145 */ 146 return false; 147} 148 149typedef struct _SwapchainBuffers { 150 VkImage image; 151 VkCmdBuffer cmd; 152 VkImageView view; 153} SwapchainBuffers; 154 155struct demo { 156#ifdef _WIN32 157#define APP_NAME_STR_LEN 80 158 HINSTANCE connection; // hInstance - Windows Instance 159 char name[APP_NAME_STR_LEN]; // Name to put on the window/icon 160 HWND window; // hWnd - window handle 161#else // _WIN32 162 xcb_connection_t *connection; 163 xcb_screen_t *screen; 164 xcb_window_t window; 165 xcb_intern_atom_reply_t *atom_wm_delete_window; 166 VkPlatformHandleXcbKHR platform_handle_xcb; 167#endif // _WIN32 168 bool prepared; 169 bool use_staging_buffer; 170 bool use_glsl; 171 172 VkInstance inst; 173 VkPhysicalDevice gpu; 174 VkDevice device; 175 VkQueue queue; 176 VkPhysicalDeviceProperties gpu_props; 177 VkQueueFamilyProperties *queue_props; 178 uint32_t graphics_queue_node_index; 179 180 int width, height; 181 VkFormat format; 182 VkColorSpaceKHR color_space; 183 184 PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR; 185 PFN_vkGetSurfacePropertiesKHR fpGetSurfacePropertiesKHR; 186 PFN_vkGetSurfaceFormatsKHR fpGetSurfaceFormatsKHR; 187 PFN_vkGetSurfacePresentModesKHR fpGetSurfacePresentModesKHR; 188 PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR; 189 PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR; 190 PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR; 191 PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR; 192 PFN_vkQueuePresentKHR fpQueuePresentKHR; 193 VkSurfaceDescriptionWindowKHR surface_description; 194 uint32_t swapchainImageCount; 195 VkSwapchainKHR swapchain; 196 SwapchainBuffers *buffers; 197 198 VkCmdPool cmd_pool; 199 200 struct { 201 VkFormat format; 202 203 VkImage image; 204 VkDeviceMemory mem; 205 VkImageView view; 206 } depth; 207 208 struct texture_object textures[DEMO_TEXTURE_COUNT]; 209 210 struct { 211 VkBuffer buf; 212 VkDeviceMemory mem; 213 214 VkPipelineVertexInputStateCreateInfo vi; 215 VkVertexInputBindingDescription vi_bindings[1]; 216 VkVertexInputAttributeDescription vi_attrs[2]; 217 } vertices; 218 219 VkCmdBuffer setup_cmd; // Command Buffer for initialization commands 220 VkCmdBuffer draw_cmd; // Command Buffer for drawing commands 221 VkPipelineLayout pipeline_layout; 222 VkDescriptorSetLayout desc_layout; 223 VkPipelineCache pipelineCache; 224 VkRenderPass render_pass; 225 VkPipeline pipeline; 226 227 VkShaderModule vert_shader_module; 228 VkShaderModule frag_shader_module; 229 230 VkDescriptorPool desc_pool; 231 VkDescriptorSet desc_set; 232 233 VkFramebuffer *framebuffers; 234 235 VkPhysicalDeviceMemoryProperties memory_properties; 236 237 bool validate; 238 PFN_vkDbgCreateMsgCallback dbgCreateMsgCallback; 239 PFN_vkDbgDestroyMsgCallback dbgDestroyMsgCallback; 240 VkDbgMsgCallback msg_callback; 241 242 float depthStencil; 243 float depthIncrement; 244 245 bool quit; 246 uint32_t current_buffer; 247 uint32_t queue_count; 248}; 249 250// Forward declaration: 251static void demo_resize(struct demo *demo); 252 253static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex) 254{ 255 // Search memtypes to find first index with those properties 256 for (uint32_t i = 0; i < 32; i++) { 257 if ((typeBits & 1) == 1) { 258 // Type is available, does it match user properties? 259 if ((demo->memory_properties.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) { 260 *typeIndex = i; 261 return true; 262 } 263 } 264 typeBits >>= 1; 265 } 266 // No memory types matched, return failure 267 return false; 268} 269 270static void demo_flush_init_cmd(struct demo *demo) 271{ 272 VkResult U_ASSERT_ONLY err; 273 274 if (demo->setup_cmd == VK_NULL_HANDLE) 275 return; 276 277 err = vkEndCommandBuffer(demo->setup_cmd); 278 assert(!err); 279 280 const VkCmdBuffer cmd_bufs[] = { demo->setup_cmd }; 281 VkFence nullFence = {VK_NULL_HANDLE}; 282 VkSubmitInfo submit_info = { 283 .waitSemCount = 0, 284 .pWaitSemaphores = NULL, 285 .cmdBufferCount = 1, 286 .pCommandBuffers = cmd_bufs, 287 .signalSemCount = 0, 288 .pSignalSemaphores = NULL 289 }; 290 291 err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence); 292 assert(!err); 293 294 err = vkQueueWaitIdle(demo->queue); 295 assert(!err); 296 297 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, cmd_bufs); 298 demo->setup_cmd = VK_NULL_HANDLE; 299} 300 301static void demo_set_image_layout( 302 struct demo *demo, 303 VkImage image, 304 VkImageAspectFlags aspectMask, 305 VkImageLayout old_image_layout, 306 VkImageLayout new_image_layout) 307{ 308 VkResult U_ASSERT_ONLY err; 309 310 if (demo->setup_cmd == VK_NULL_HANDLE) { 311 const VkCmdBufferAllocInfo cmd = { 312 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_ALLOC_INFO, 313 .pNext = NULL, 314 .cmdPool = demo->cmd_pool, 315 .level = VK_CMD_BUFFER_LEVEL_PRIMARY, 316 .count = 1, 317 }; 318 319 err = vkAllocCommandBuffers(demo->device, &cmd, &demo->setup_cmd); 320 assert(!err); 321 322 VkCmdBufferBeginInfo cmd_buf_info = { 323 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, 324 .pNext = NULL, 325 .flags = 0, 326 .renderPass = { VK_NULL_HANDLE }, 327 .subpass = 0, 328 .framebuffer = { VK_NULL_HANDLE }, 329 }; 330 err = vkBeginCommandBuffer(demo->setup_cmd, &cmd_buf_info); 331 assert(!err); 332 } 333 334 VkImageMemoryBarrier image_memory_barrier = { 335 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 336 .pNext = NULL, 337 .outputMask = 0, 338 .inputMask = 0, 339 .oldLayout = old_image_layout, 340 .newLayout = new_image_layout, 341 .image = image, 342 .subresourceRange = { aspectMask, 0, 1, 0, 0 } 343 }; 344 345 if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL) { 346 /* Make sure anything that was copying from this image has completed */ 347 image_memory_barrier.inputMask = VK_MEMORY_INPUT_TRANSFER_BIT; 348 } 349 350 if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 351 /* Make sure any Copy or CPU writes to image are flushed */ 352 image_memory_barrier.outputMask = VK_MEMORY_OUTPUT_TRANSFER_BIT | VK_MEMORY_OUTPUT_HOST_WRITE_BIT; 353 } 354 355 VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier; 356 357 VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 358 VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 359 360 vkCmdPipelineBarrier(demo->setup_cmd, src_stages, dest_stages, false, 1, (const void * const*)&pmemory_barrier); 361} 362 363static void demo_draw_build_cmd(struct demo *demo) 364{ 365 const VkCmdBufferBeginInfo cmd_buf_info = { 366 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, 367 .pNext = NULL, 368 .flags = 0, 369 .renderPass = { VK_NULL_HANDLE }, 370 .subpass = 0, 371 .framebuffer = { VK_NULL_HANDLE }, 372 }; 373 const VkClearValue clear_values[2] = { 374 [0] = { .color.float32 = { 0.2f, 0.2f, 0.2f, 0.2f } }, 375 [1] = { .depthStencil = { demo->depthStencil, 0 } }, 376 }; 377 const VkRenderPassBeginInfo rp_begin = { 378 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 379 .pNext = NULL, 380 .renderPass = demo->render_pass, 381 .framebuffer = demo->framebuffers[demo->current_buffer], 382 .renderArea.offset.x = 0, 383 .renderArea.offset.y = 0, 384 .renderArea.extent.width = demo->width, 385 .renderArea.extent.height = demo->height, 386 .clearValueCount = 2, 387 .pClearValues = clear_values, 388 }; 389 VkResult U_ASSERT_ONLY err; 390 391 err = vkBeginCommandBuffer(demo->draw_cmd, &cmd_buf_info); 392 assert(!err); 393 394 vkCmdBeginRenderPass(demo->draw_cmd, &rp_begin, VK_RENDER_PASS_CONTENTS_INLINE); 395 vkCmdBindPipeline(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, 396 demo->pipeline); 397 vkCmdBindDescriptorSets(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline_layout, 398 0, 1, & demo->desc_set, 0, NULL); 399 400 VkViewport viewport; 401 memset(&viewport, 0, sizeof(viewport)); 402 viewport.height = (float) demo->height; 403 viewport.width = (float) demo->width; 404 viewport.minDepth = (float) 0.0f; 405 viewport.maxDepth = (float) 1.0f; 406 vkCmdSetViewport(demo->draw_cmd, 1, &viewport); 407 408 VkRect2D scissor; 409 memset(&scissor, 0, sizeof(scissor)); 410 scissor.extent.width = demo->width; 411 scissor.extent.height = demo->height; 412 scissor.offset.x = 0; 413 scissor.offset.y = 0; 414 vkCmdSetScissor(demo->draw_cmd, 1, &scissor); 415 416 VkDeviceSize offsets[1] = {0}; 417 vkCmdBindVertexBuffers(demo->draw_cmd, VERTEX_BUFFER_BIND_ID, 1, &demo->vertices.buf, offsets); 418 419 vkCmdDraw(demo->draw_cmd, 3, 1, 0, 0); 420 vkCmdEndRenderPass(demo->draw_cmd); 421 422 VkImageMemoryBarrier prePresentBarrier = { 423 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 424 .pNext = NULL, 425 .outputMask = VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT, 426 .inputMask = 0, 427 .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 428 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SOURCE_KHR, 429 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 430 .destQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 431 .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } 432 }; 433 434 prePresentBarrier.image = demo->buffers[demo->current_buffer].image; 435 VkImageMemoryBarrier *pmemory_barrier = &prePresentBarrier; 436 vkCmdPipelineBarrier(demo->draw_cmd, VK_PIPELINE_STAGE_ALL_GPU_COMMANDS, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 437 VK_FALSE, 1, (const void * const*)&pmemory_barrier); 438 439 err = vkEndCommandBuffer(demo->draw_cmd); 440 assert(!err); 441} 442 443static void demo_draw(struct demo *demo) 444{ 445 VkResult U_ASSERT_ONLY err; 446 VkSemaphore presentCompleteSemaphore; 447 VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = { 448 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 449 .pNext = NULL, 450 .flags = 0, 451 }; 452 453 err = vkCreateSemaphore(demo->device, 454 &presentCompleteSemaphoreCreateInfo, 455 &presentCompleteSemaphore); 456 assert(!err); 457 458 // Get the index of the next available swapchain image: 459 err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, 460 UINT64_MAX, 461 presentCompleteSemaphore, 462 &demo->current_buffer); 463 if (err == VK_ERROR_OUT_OF_DATE_KHR) { 464 // demo->swapchain is out of date (e.g. the window was resized) and 465 // must be recreated: 466 demo_resize(demo); 467 demo_draw(demo); 468 vkDestroySemaphore(demo->device, presentCompleteSemaphore); 469 return; 470 } else if (err == VK_SUBOPTIMAL_KHR) { 471 // demo->swapchain is not as optimal as it could be, but the platform's 472 // presentation engine will still present the image correctly. 473 } else { 474 assert(!err); 475 } 476 477 // Assume the command buffer has been run on current_buffer before so 478 // we need to set the image layout back to COLOR_ATTACHMENT_OPTIMAL 479 demo_set_image_layout(demo, demo->buffers[demo->current_buffer].image, 480 VK_IMAGE_ASPECT_COLOR_BIT, 481 VK_IMAGE_LAYOUT_PRESENT_SOURCE_KHR, 482 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 483 demo_flush_init_cmd(demo); 484 485 // Wait for the present complete semaphore to be signaled to ensure 486 // that the image won't be rendered to until the presentation 487 // engine has fully released ownership to the application, and it is 488 // okay to render to the image. 489 490// FIXME/TODO: DEAL WITH VK_IMAGE_LAYOUT_PRESENT_SOURCE_KHR 491 demo_draw_build_cmd(demo); 492 VkFence nullFence = { VK_NULL_HANDLE }; 493 494 VkSubmitInfo submit_info = { 495 .waitSemCount = 1, 496 .pWaitSemaphores = &presentCompleteSemaphore, 497 .cmdBufferCount = 1, 498 .pCommandBuffers = &demo->draw_cmd, 499 .signalSemCount = 0, 500 .pSignalSemaphores = NULL 501 }; 502 503 err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence); 504 assert(!err); 505 506 VkPresentInfoKHR present = { 507 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 508 .pNext = NULL, 509 .swapchainCount = 1, 510 .swapchains = &demo->swapchain, 511 .imageIndices = &demo->current_buffer, 512 }; 513 514// TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER? 515 err = demo->fpQueuePresentKHR(demo->queue, &present); 516 if (err == VK_ERROR_OUT_OF_DATE_KHR) { 517 // demo->swapchain is out of date (e.g. the window was resized) and 518 // must be recreated: 519 demo_resize(demo); 520 } else if (err == VK_SUBOPTIMAL_KHR) { 521 // demo->swapchain is not as optimal as it could be, but the platform's 522 // presentation engine will still present the image correctly. 523 } else { 524 assert(!err); 525 } 526 527 err = vkQueueWaitIdle(demo->queue); 528 assert(err == VK_SUCCESS); 529 530 vkDestroySemaphore(demo->device, presentCompleteSemaphore); 531} 532 533static void demo_prepare_buffers(struct demo *demo) 534{ 535 VkResult U_ASSERT_ONLY err; 536 VkSwapchainKHR oldSwapchain = demo->swapchain; 537 538 // Check the surface proprties and formats 539 VkSurfacePropertiesKHR surfProperties; 540 err = demo->fpGetSurfacePropertiesKHR(demo->device, 541 (const VkSurfaceDescriptionKHR *)&demo->surface_description, 542 &surfProperties); 543 assert(!err); 544 545 uint32_t presentModeCount; 546 err = demo->fpGetSurfacePresentModesKHR(demo->device, 547 (const VkSurfaceDescriptionKHR *)&demo->surface_description, 548 &presentModeCount, NULL); 549 assert(!err); 550 VkPresentModeKHR *presentModes = 551 (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR)); 552 assert(presentModes); 553 err = demo->fpGetSurfacePresentModesKHR(demo->device, 554 (const VkSurfaceDescriptionKHR *)&demo->surface_description, 555 &presentModeCount, presentModes); 556 assert(!err); 557 558 VkExtent2D swapchainExtent; 559 // width and height are either both -1, or both not -1. 560 if (surfProperties.currentExtent.width == -1) 561 { 562 // If the surface size is undefined, the size is set to 563 // the size of the images requested. 564 swapchainExtent.width = demo->width; 565 swapchainExtent.height = demo->height; 566 } 567 else 568 { 569 // If the surface size is defined, the swap chain size must match 570 swapchainExtent = surfProperties.currentExtent; 571 demo->width = surfProperties.currentExtent.width; 572 demo->height = surfProperties.currentExtent.height; 573 } 574 575 VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; 576 577 // Determine the number of VkImage's to use in the swap chain (we desire to 578 // own only 1 image at a time, besides the images being displayed and 579 // queued for display): 580 uint32_t desiredNumberOfSwapchainImages = surfProperties.minImageCount + 1; 581 if ((surfProperties.maxImageCount > 0) && 582 (desiredNumberOfSwapchainImages > surfProperties.maxImageCount)) 583 { 584 // Application must settle for fewer images than desired: 585 desiredNumberOfSwapchainImages = surfProperties.maxImageCount; 586 } 587 588 VkSurfaceTransformKHR preTransform; 589 if (surfProperties.supportedTransforms & VK_SURFACE_TRANSFORM_NONE_BIT_KHR) { 590 preTransform = VK_SURFACE_TRANSFORM_NONE_KHR; 591 } else { 592 preTransform = surfProperties.currentTransform; 593 } 594 595 const VkSwapchainCreateInfoKHR swapchain = { 596 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 597 .pNext = NULL, 598 .pSurfaceDescription = (const VkSurfaceDescriptionKHR *)&demo->surface_description, 599 .minImageCount = desiredNumberOfSwapchainImages, 600 .imageFormat = demo->format, 601 .imageColorSpace = demo->color_space, 602 .imageExtent = { 603 .width = swapchainExtent.width, 604 .height = swapchainExtent.height, 605 }, 606 .imageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 607 .preTransform = preTransform, 608 .imageArraySize = 1, 609 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 610 .queueFamilyCount = 0, 611 .pQueueFamilyIndices = NULL, 612 .presentMode = swapchainPresentMode, 613 .oldSwapchain = oldSwapchain, 614 .clipped = true, 615 }; 616 uint32_t i; 617 618 err = demo->fpCreateSwapchainKHR(demo->device, &swapchain, &demo->swapchain); 619 assert(!err); 620 621 // If we just re-created an existing swapchain, we should destroy the old 622 // swapchain at this point. 623 // Note: destroying the swapchain also cleans up all its associated 624 // presentable images once the platform is done with them. 625 if (oldSwapchain.handle != VK_NULL_HANDLE) { 626 demo->fpDestroySwapchainKHR(demo->device, oldSwapchain); 627 } 628 629 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain, 630 &demo->swapchainImageCount, NULL); 631 assert(!err); 632 633 VkImage* swapchainImages = 634 (VkImage*)malloc(demo->swapchainImageCount * sizeof(VkImage)); 635 assert(swapchainImages); 636 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain, 637 &demo->swapchainImageCount, 638 swapchainImages); 639 assert(!err); 640 641 demo->buffers = (SwapchainBuffers*)malloc(sizeof(SwapchainBuffers)*demo->swapchainImageCount); 642 assert(demo->buffers); 643 644 for (i = 0; i < demo->swapchainImageCount; i++) { 645 VkImageViewCreateInfo color_attachment_view = { 646 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 647 .pNext = NULL, 648 .format = demo->format, 649 .channels = { 650 .r = VK_CHANNEL_SWIZZLE_R, 651 .g = VK_CHANNEL_SWIZZLE_G, 652 .b = VK_CHANNEL_SWIZZLE_B, 653 .a = VK_CHANNEL_SWIZZLE_A, 654 }, 655 .subresourceRange = { 656 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 657 .baseMipLevel = 0, 658 .numLevels = 1, 659 .baseArrayLayer = 0, 660 .numLayers = 1 661 }, 662 .viewType = VK_IMAGE_VIEW_TYPE_2D, 663 .flags = 0, 664 }; 665 666 demo->buffers[i].image = swapchainImages[i]; 667 668 // Render loop will expect image to have been used before and in VK_IMAGE_LAYOUT_PRESENT_SOURCE_KHR 669 // layout and will change to COLOR_ATTACHMENT_OPTIMAL, so init the image to that state 670 demo_set_image_layout(demo, demo->buffers[i].image, 671 VK_IMAGE_ASPECT_COLOR_BIT, 672 VK_IMAGE_LAYOUT_UNDEFINED, 673 VK_IMAGE_LAYOUT_PRESENT_SOURCE_KHR); 674 675 color_attachment_view.image = demo->buffers[i].image; 676 677 err = vkCreateImageView(demo->device, 678 &color_attachment_view, &demo->buffers[i].view); 679 assert(!err); 680 } 681 682 demo->current_buffer = 0; 683} 684 685static void demo_prepare_depth(struct demo *demo) 686{ 687 const VkFormat depth_format = VK_FORMAT_D16_UNORM; 688 const VkImageCreateInfo image = { 689 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 690 .pNext = NULL, 691 .imageType = VK_IMAGE_TYPE_2D, 692 .format = depth_format, 693 .extent = { demo->width, demo->height, 1 }, 694 .mipLevels = 1, 695 .arrayLayers = 1, 696 .samples = 1, 697 .tiling = VK_IMAGE_TILING_OPTIMAL, 698 .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 699 .flags = 0, 700 }; 701 VkMemoryAllocInfo mem_alloc = { 702 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 703 .pNext = NULL, 704 .allocationSize = 0, 705 .memoryTypeIndex = 0, 706 }; 707 VkImageViewCreateInfo view = { 708 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 709 .pNext = NULL, 710 .image.handle = VK_NULL_HANDLE, 711 .format = depth_format, 712 .subresourceRange = { 713 .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, 714 .baseMipLevel = 0, 715 .numLevels = 1, 716 .baseArrayLayer = 0, 717 .numLayers = 1 718 }, 719 .flags = 0, 720 .viewType = VK_IMAGE_VIEW_TYPE_2D, 721 }; 722 723 VkMemoryRequirements mem_reqs; 724 VkResult U_ASSERT_ONLY err; 725 bool U_ASSERT_ONLY pass; 726 727 demo->depth.format = depth_format; 728 729 /* create image */ 730 err = vkCreateImage(demo->device, &image, 731 &demo->depth.image); 732 assert(!err); 733 734 /* get memory requirements for this object */ 735 vkGetImageMemoryRequirements(demo->device, demo->depth.image, 736 &mem_reqs); 737 738 /* select memory size and type */ 739 mem_alloc.allocationSize = mem_reqs.size; 740 pass = memory_type_from_properties(demo, 741 mem_reqs.memoryTypeBits, 742 0, /* No requirements */ 743 &mem_alloc.memoryTypeIndex); 744 assert(pass); 745 746 /* allocate memory */ 747 err = vkAllocMemory(demo->device, &mem_alloc, &demo->depth.mem); 748 assert(!err); 749 750 /* bind memory */ 751 err = vkBindImageMemory(demo->device, demo->depth.image, 752 demo->depth.mem, 0); 753 assert(!err); 754 755 demo_set_image_layout(demo, demo->depth.image, 756 VK_IMAGE_ASPECT_DEPTH_BIT, 757 VK_IMAGE_LAYOUT_UNDEFINED, 758 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); 759 760 /* create image view */ 761 view.image = demo->depth.image; 762 err = vkCreateImageView(demo->device, &view, &demo->depth.view); 763 assert(!err); 764} 765 766static void demo_prepare_texture_image(struct demo *demo, 767 const uint32_t *tex_colors, 768 struct texture_object *tex_obj, 769 VkImageTiling tiling, 770 VkImageUsageFlags usage, 771 VkFlags required_props) 772{ 773 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; 774 const int32_t tex_width = 2; 775 const int32_t tex_height = 2; 776 VkResult U_ASSERT_ONLY err; 777 bool U_ASSERT_ONLY pass; 778 779 tex_obj->tex_width = tex_width; 780 tex_obj->tex_height = tex_height; 781 782 const VkImageCreateInfo image_create_info = { 783 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 784 .pNext = NULL, 785 .imageType = VK_IMAGE_TYPE_2D, 786 .format = tex_format, 787 .extent = { tex_width, tex_height, 1 }, 788 .mipLevels = 1, 789 .arrayLayers = 1, 790 .samples = 1, 791 .tiling = tiling, 792 .usage = usage, 793 .flags = 0, 794 }; 795 VkMemoryAllocInfo mem_alloc = { 796 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 797 .pNext = NULL, 798 .allocationSize = 0, 799 .memoryTypeIndex = 0, 800 }; 801 802 VkMemoryRequirements mem_reqs; 803 804 err = vkCreateImage(demo->device, &image_create_info, 805 &tex_obj->image); 806 assert(!err); 807 808 vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs); 809 810 mem_alloc.allocationSize = mem_reqs.size; 811 pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, required_props, &mem_alloc.memoryTypeIndex); 812 assert(pass); 813 814 /* allocate memory */ 815 err = vkAllocMemory(demo->device, &mem_alloc, &tex_obj->mem); 816 assert(!err); 817 818 /* bind memory */ 819 err = vkBindImageMemory(demo->device, tex_obj->image, 820 tex_obj->mem, 0); 821 assert(!err); 822 823 if (required_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { 824 const VkImageSubresource subres = { 825 .aspect = VK_IMAGE_ASPECT_COLOR_BIT, 826 .mipLevel = 0, 827 .arrayLayer = 0, 828 }; 829 VkSubresourceLayout layout; 830 void *data; 831 int32_t x, y; 832 833 vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres, &layout); 834 835 err = vkMapMemory(demo->device, tex_obj->mem, 0, mem_alloc.allocationSize, 0, &data); 836 assert(!err); 837 838 for (y = 0; y < tex_height; y++) { 839 uint32_t *row = (uint32_t *) ((char *) data + layout.rowPitch * y); 840 for (x = 0; x < tex_width; x++) 841 row[x] = tex_colors[(x & 1) ^ (y & 1)]; 842 } 843 844 vkUnmapMemory(demo->device, tex_obj->mem); 845 } 846 847 tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 848 demo_set_image_layout(demo, tex_obj->image, 849 VK_IMAGE_ASPECT_COLOR_BIT, 850 VK_IMAGE_LAYOUT_UNDEFINED, 851 tex_obj->imageLayout); 852 /* setting the image layout does not reference the actual memory so no need to add a mem ref */ 853} 854 855static void demo_destroy_texture_image(struct demo *demo, struct texture_object *tex_obj) 856{ 857 /* clean up staging resources */ 858 vkDestroyImage(demo->device, tex_obj->image); 859 vkFreeMemory(demo->device, tex_obj->mem); 860} 861 862static void demo_prepare_textures(struct demo *demo) 863{ 864 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; 865 VkFormatProperties props; 866 const uint32_t tex_colors[DEMO_TEXTURE_COUNT][2] = { 867 { 0xffff0000, 0xff00ff00 }, 868 }; 869 uint32_t i; 870 VkResult err; 871 872 vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props); 873 874 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 875 if ((props.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && !demo->use_staging_buffer) { 876 /* Device can texture using linear textures */ 877 demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i], 878 VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); 879 } else if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT){ 880 /* Must use staging buffer to copy linear texture to optimized */ 881 struct texture_object staging_texture; 882 883 memset(&staging_texture, 0, sizeof(staging_texture)); 884 demo_prepare_texture_image(demo, tex_colors[i], &staging_texture, 885 VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); 886 887 demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i], 888 VK_IMAGE_TILING_OPTIMAL, 889 (VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT | VK_IMAGE_USAGE_SAMPLED_BIT), 890 VK_MEMORY_PROPERTY_DEVICE_ONLY); 891 892 demo_set_image_layout(demo, staging_texture.image, 893 VK_IMAGE_ASPECT_COLOR_BIT, 894 staging_texture.imageLayout, 895 VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL); 896 897 demo_set_image_layout(demo, demo->textures[i].image, 898 VK_IMAGE_ASPECT_COLOR_BIT, 899 demo->textures[i].imageLayout, 900 VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL); 901 902 VkImageCopy copy_region = { 903 .srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 }, 904 .srcOffset = { 0, 0, 0 }, 905 .destSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 }, 906 .destOffset = { 0, 0, 0 }, 907 .extent = { staging_texture.tex_width, staging_texture.tex_height, 1 }, 908 }; 909 vkCmdCopyImage(demo->setup_cmd, 910 staging_texture.image, VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, 911 demo->textures[i].image, VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, 912 1, ©_region); 913 914 demo_set_image_layout(demo, demo->textures[i].image, 915 VK_IMAGE_ASPECT_COLOR_BIT, 916 VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, 917 demo->textures[i].imageLayout); 918 919 demo_flush_init_cmd(demo); 920 921 demo_destroy_texture_image(demo, &staging_texture); 922 } else { 923 /* Can't support VK_FORMAT_B8G8R8A8_UNORM !? */ 924 assert(!"No support for B8G8R8A8_UNORM as texture image format"); 925 } 926 927 const VkSamplerCreateInfo sampler = { 928 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 929 .pNext = NULL, 930 .magFilter = VK_TEX_FILTER_NEAREST, 931 .minFilter = VK_TEX_FILTER_NEAREST, 932 .mipMode = VK_TEX_MIPMAP_MODE_BASE, 933 .addressModeU = VK_TEX_ADDRESS_MODE_WRAP, 934 .addressModeV = VK_TEX_ADDRESS_MODE_WRAP, 935 .addressModeW = VK_TEX_ADDRESS_MODE_WRAP, 936 .mipLodBias = 0.0f, 937 .maxAnisotropy = 1, 938 .compareOp = VK_COMPARE_OP_NEVER, 939 .minLod = 0.0f, 940 .maxLod = 0.0f, 941 .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, 942 .unnormalizedCoordinates = VK_FALSE, 943 }; 944 VkImageViewCreateInfo view = { 945 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 946 .pNext = NULL, 947 .image.handle = VK_NULL_HANDLE, 948 .viewType = VK_IMAGE_VIEW_TYPE_2D, 949 .format = tex_format, 950 .channels = { VK_CHANNEL_SWIZZLE_R, 951 VK_CHANNEL_SWIZZLE_G, 952 VK_CHANNEL_SWIZZLE_B, 953 VK_CHANNEL_SWIZZLE_A, }, 954 .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, 955 .flags = 0, 956 }; 957 958 /* create sampler */ 959 err = vkCreateSampler(demo->device, &sampler, 960 &demo->textures[i].sampler); 961 assert(!err); 962 963 /* create image view */ 964 view.image = demo->textures[i].image; 965 err = vkCreateImageView(demo->device, &view, 966 &demo->textures[i].view); 967 assert(!err); 968 } 969} 970 971static void demo_prepare_vertices(struct demo *demo) 972{ 973 const float vb[3][5] = { 974 /* position texcoord */ 975 { -1.0f, -1.0f, 0.25f, 0.0f, 0.0f }, 976 { 1.0f, -1.0f, 0.25f, 1.0f, 0.0f }, 977 { 0.0f, 1.0f, 1.0f, 0.5f, 1.0f }, 978 }; 979 const VkBufferCreateInfo buf_info = { 980 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 981 .pNext = NULL, 982 .size = sizeof(vb), 983 .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 984 .flags = 0, 985 }; 986 VkMemoryAllocInfo mem_alloc = { 987 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 988 .pNext = NULL, 989 .allocationSize = 0, 990 .memoryTypeIndex = 0, 991 }; 992 VkMemoryRequirements mem_reqs; 993 VkResult U_ASSERT_ONLY err; 994 bool U_ASSERT_ONLY pass; 995 void *data; 996 997 memset(&demo->vertices, 0, sizeof(demo->vertices)); 998 999 err = vkCreateBuffer(demo->device, &buf_info, &demo->vertices.buf); 1000 assert(!err); 1001 1002 vkGetBufferMemoryRequirements(demo->device, 1003 demo->vertices.buf, &mem_reqs); 1004 assert(!err); 1005 1006 mem_alloc.allocationSize = mem_reqs.size; 1007 pass = memory_type_from_properties(demo, 1008 mem_reqs.memoryTypeBits, 1009 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 1010 &mem_alloc.memoryTypeIndex); 1011 assert(pass); 1012 1013 err = vkAllocMemory(demo->device, &mem_alloc, &demo->vertices.mem); 1014 assert(!err); 1015 1016 err = vkMapMemory(demo->device, demo->vertices.mem, 0, mem_alloc.allocationSize, 0, &data); 1017 assert(!err); 1018 1019 memcpy(data, vb, sizeof(vb)); 1020 1021 vkUnmapMemory(demo->device, demo->vertices.mem); 1022 1023 err = vkBindBufferMemory(demo->device, demo->vertices.buf, 1024 demo->vertices.mem, 0); 1025 assert(!err); 1026 1027 demo->vertices.vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 1028 demo->vertices.vi.pNext = NULL; 1029 demo->vertices.vi.bindingCount = 1; 1030 demo->vertices.vi.pVertexBindingDescriptions = demo->vertices.vi_bindings; 1031 demo->vertices.vi.attributeCount = 2; 1032 demo->vertices.vi.pVertexAttributeDescriptions = demo->vertices.vi_attrs; 1033 1034 demo->vertices.vi_bindings[0].binding = VERTEX_BUFFER_BIND_ID; 1035 demo->vertices.vi_bindings[0].strideInBytes = sizeof(vb[0]); 1036 demo->vertices.vi_bindings[0].stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX; 1037 1038 demo->vertices.vi_attrs[0].binding = VERTEX_BUFFER_BIND_ID; 1039 demo->vertices.vi_attrs[0].location = 0; 1040 demo->vertices.vi_attrs[0].format = VK_FORMAT_R32G32B32_SFLOAT; 1041 demo->vertices.vi_attrs[0].offsetInBytes = 0; 1042 1043 demo->vertices.vi_attrs[1].binding = VERTEX_BUFFER_BIND_ID; 1044 demo->vertices.vi_attrs[1].location = 1; 1045 demo->vertices.vi_attrs[1].format = VK_FORMAT_R32G32_SFLOAT; 1046 demo->vertices.vi_attrs[1].offsetInBytes = sizeof(float) * 3; 1047} 1048 1049static void demo_prepare_descriptor_layout(struct demo *demo) 1050{ 1051 const VkDescriptorSetLayoutBinding layout_binding = { 1052 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1053 .arraySize = DEMO_TEXTURE_COUNT, 1054 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, 1055 .pImmutableSamplers = NULL, 1056 }; 1057 const VkDescriptorSetLayoutCreateInfo descriptor_layout = { 1058 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 1059 .pNext = NULL, 1060 .count = 1, 1061 .pBinding = &layout_binding, 1062 }; 1063 VkResult U_ASSERT_ONLY err; 1064 1065 err = vkCreateDescriptorSetLayout(demo->device, 1066 &descriptor_layout, &demo->desc_layout); 1067 assert(!err); 1068 1069 const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = { 1070 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 1071 .pNext = NULL, 1072 .descriptorSetCount = 1, 1073 .pSetLayouts = &demo->desc_layout, 1074 }; 1075 1076 err = vkCreatePipelineLayout(demo->device, 1077 &pPipelineLayoutCreateInfo, 1078 &demo->pipeline_layout); 1079 assert(!err); 1080} 1081 1082static void demo_prepare_render_pass(struct demo *demo) 1083{ 1084 const VkAttachmentDescription attachments[2] = { 1085 [0] = { 1086 .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION, 1087 .pNext = NULL, 1088 .format = demo->format, 1089 .samples = 1, 1090 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 1091 .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 1092 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 1093 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1094 .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1095 .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1096 }, 1097 [1] = { 1098 .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION, 1099 .pNext = NULL, 1100 .format = demo->depth.format, 1101 .samples = 1, 1102 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 1103 .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1104 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 1105 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1106 .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1107 .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1108 }, 1109 }; 1110 const VkAttachmentReference color_reference = { 1111 .attachment = 0, 1112 .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1113 }; 1114 const VkSubpassDescription subpass = { 1115 .sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION, 1116 .pNext = NULL, 1117 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, 1118 .flags = 0, 1119 .inputCount = 0, 1120 .pInputAttachments = NULL, 1121 .colorCount = 1, 1122 .pColorAttachments = &color_reference, 1123 .pResolveAttachments = NULL, 1124 .depthStencilAttachment = { 1125 .attachment = 1, 1126 .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1127 }, 1128 .preserveCount = 0, 1129 .pPreserveAttachments = NULL, 1130 }; 1131 const VkRenderPassCreateInfo rp_info = { 1132 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 1133 .pNext = NULL, 1134 .attachmentCount = 2, 1135 .pAttachments = attachments, 1136 .subpassCount = 1, 1137 .pSubpasses = &subpass, 1138 .dependencyCount = 0, 1139 .pDependencies = NULL, 1140 }; 1141 VkResult U_ASSERT_ONLY err; 1142 1143 err = vkCreateRenderPass(demo->device, &rp_info, &demo->render_pass); 1144 assert(!err); 1145} 1146 1147static VkShader demo_prepare_shader(struct demo *demo, 1148 VkShaderStageFlagBits stage, 1149 VkShaderModule* pShaderModule, 1150 const void *code, 1151 size_t size) 1152{ 1153 VkShaderModuleCreateInfo moduleCreateInfo; 1154 VkShaderCreateInfo shaderCreateInfo; 1155 VkShader shader; 1156 VkResult U_ASSERT_ONLY err; 1157 1158 1159 moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 1160 moduleCreateInfo.pNext = NULL; 1161 1162 shaderCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO; 1163 shaderCreateInfo.pNext = NULL; 1164 1165 if (!demo->use_glsl) { 1166 moduleCreateInfo.codeSize = size; 1167 moduleCreateInfo.pCode = code; 1168 moduleCreateInfo.flags = 0; 1169 err = vkCreateShaderModule(demo->device, &moduleCreateInfo, pShaderModule); 1170 assert(!err); 1171 1172 shaderCreateInfo.flags = 0; 1173 shaderCreateInfo.module = *pShaderModule; 1174 shaderCreateInfo.pName = "main"; 1175 shaderCreateInfo.stage = stage; 1176 err = vkCreateShader(demo->device, &shaderCreateInfo, &shader); 1177 assert(!err); 1178 } else { 1179 // Create fake SPV structure to feed GLSL 1180 // to the driver "under the covers" 1181 moduleCreateInfo.codeSize = 3 * sizeof(uint32_t) + size + 1; 1182 moduleCreateInfo.pCode = malloc(moduleCreateInfo.codeSize); 1183 moduleCreateInfo.flags = 0; 1184 1185 /* try version 0 first: VkShaderStage followed by GLSL */ 1186 ((uint32_t *) moduleCreateInfo.pCode)[0] = ICD_SPV_MAGIC; 1187 ((uint32_t *) moduleCreateInfo.pCode)[1] = 0; 1188 ((uint32_t *) moduleCreateInfo.pCode)[2] = stage; 1189 memcpy(((uint32_t *) moduleCreateInfo.pCode + 3), code, size + 1); 1190 1191 err = vkCreateShaderModule(demo->device, &moduleCreateInfo, pShaderModule); 1192 assert(!err); 1193 1194 shaderCreateInfo.flags = 0; 1195 shaderCreateInfo.module = *pShaderModule; 1196 shaderCreateInfo.pName = "main"; 1197 shaderCreateInfo.stage = stage; 1198 err = vkCreateShader(demo->device, &shaderCreateInfo, &shader); 1199 assert(!err); 1200 free((void *) moduleCreateInfo.pCode); 1201 } 1202 return shader; 1203} 1204 1205char *demo_read_spv(const char *filename, size_t *psize) 1206{ 1207 long int size; 1208 void *shader_code; 1209 size_t retVal; 1210 1211 FILE *fp = fopen(filename, "rb"); 1212 if (!fp) return NULL; 1213 1214 fseek(fp, 0L, SEEK_END); 1215 size = ftell(fp); 1216 1217 fseek(fp, 0L, SEEK_SET); 1218 1219 shader_code = malloc(size); 1220 retVal = fread(shader_code, size, 1, fp); 1221 if (!retVal) return NULL; 1222 1223 *psize = size; 1224 1225 fclose(fp); 1226 return shader_code; 1227} 1228 1229static VkShader demo_prepare_vs(struct demo *demo) 1230{ 1231 if (!demo->use_glsl) { 1232 VkShader shader; 1233 void *vertShaderCode; 1234 size_t size; 1235 1236 vertShaderCode = demo_read_spv("tri-vert.spv", &size); 1237 1238 shader = demo_prepare_shader(demo, VK_SHADER_STAGE_VERTEX_BIT, 1239 &demo->vert_shader_module, 1240 vertShaderCode, size); 1241 free(vertShaderCode); 1242 return shader; 1243 } else { 1244 static const char *vertShaderText = 1245 "#version 140\n" 1246 "#extension GL_ARB_separate_shader_objects : enable\n" 1247 "#extension GL_ARB_shading_language_420pack : enable\n" 1248 "layout (location = 0) in vec4 pos;\n" 1249 "layout (location = 1) in vec2 attr;\n" 1250 "out vec2 texcoord;\n" 1251 "void main() {\n" 1252 " texcoord = attr;\n" 1253 " gl_Position = pos;\n" 1254 "}\n"; 1255 1256 return demo_prepare_shader(demo, VK_SHADER_STAGE_VERTEX_BIT, 1257 &demo->vert_shader_module, 1258 (const void *) vertShaderText, 1259 strlen(vertShaderText)); 1260 } 1261} 1262 1263static VkShader demo_prepare_fs(struct demo *demo) 1264{ 1265 if (!demo->use_glsl) { 1266 VkShader shader; 1267 void *fragShaderCode; 1268 size_t size; 1269 1270 fragShaderCode = demo_read_spv("tri-frag.spv", &size); 1271 1272 shader = demo_prepare_shader(demo, VK_SHADER_STAGE_FRAGMENT_BIT, 1273 &demo->frag_shader_module, 1274 fragShaderCode, size); 1275 1276 free(fragShaderCode); 1277 return shader; 1278 } else { 1279 static const char *fragShaderText = 1280 "#version 140\n" 1281 "#extension GL_ARB_separate_shader_objects : enable\n" 1282 "#extension GL_ARB_shading_language_420pack : enable\n" 1283 "layout (binding = 0) uniform sampler2D tex;\n" 1284 "layout (location = 0) in vec2 texcoord;\n" 1285 "layout (location = 0) out vec4 uFragColor;\n" 1286 "void main() {\n" 1287 " uFragColor = texture(tex, texcoord);\n" 1288 "}\n"; 1289 1290 return demo_prepare_shader(demo, VK_SHADER_STAGE_FRAGMENT_BIT, 1291 &demo->frag_shader_module, 1292 (const void *) fragShaderText, 1293 strlen(fragShaderText)); 1294 } 1295} 1296 1297static void demo_prepare_pipeline(struct demo *demo) 1298{ 1299 VkGraphicsPipelineCreateInfo pipeline; 1300 VkPipelineCacheCreateInfo pipelineCache; 1301 1302 VkPipelineVertexInputStateCreateInfo vi; 1303 VkPipelineInputAssemblyStateCreateInfo ia; 1304 VkPipelineRasterStateCreateInfo rs; 1305 VkPipelineColorBlendStateCreateInfo cb; 1306 VkPipelineDepthStencilStateCreateInfo ds; 1307 VkPipelineViewportStateCreateInfo vp; 1308 VkPipelineMultisampleStateCreateInfo ms; 1309 VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_NUM]; 1310 VkPipelineDynamicStateCreateInfo dynamicState; 1311 1312 VkResult U_ASSERT_ONLY err; 1313 1314 memset(dynamicStateEnables, 0, sizeof dynamicStateEnables); 1315 memset(&dynamicState, 0, sizeof dynamicState); 1316 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; 1317 dynamicState.pDynamicStates = dynamicStateEnables; 1318 1319 memset(&pipeline, 0, sizeof(pipeline)); 1320 pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 1321 pipeline.layout = demo->pipeline_layout; 1322 1323 vi = demo->vertices.vi; 1324 1325 memset(&ia, 0, sizeof(ia)); 1326 ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 1327 ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 1328 1329 memset(&rs, 0, sizeof(rs)); 1330 rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO; 1331 rs.fillMode = VK_FILL_MODE_SOLID; 1332 rs.cullMode = VK_CULL_MODE_BACK; 1333 rs.frontFace = VK_FRONT_FACE_CW; 1334 rs.depthClampEnable = VK_FALSE; 1335 rs.rasterizerDiscardEnable = VK_FALSE; 1336 rs.depthBiasEnable = VK_FALSE; 1337 1338 memset(&cb, 0, sizeof(cb)); 1339 cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 1340 VkPipelineColorBlendAttachmentState att_state[1]; 1341 memset(att_state, 0, sizeof(att_state)); 1342 att_state[0].channelWriteMask = 0xf; 1343 att_state[0].blendEnable = VK_FALSE; 1344 cb.attachmentCount = 1; 1345 cb.pAttachments = att_state; 1346 1347 memset(&vp, 0, sizeof(vp)); 1348 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 1349 vp.viewportCount = 1; 1350 dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT; 1351 vp.scissorCount = 1; 1352 dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR; 1353 1354 memset(&ds, 0, sizeof(ds)); 1355 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; 1356 ds.depthTestEnable = VK_TRUE; 1357 ds.depthWriteEnable = VK_TRUE; 1358 ds.depthCompareOp = VK_COMPARE_OP_LESS_EQUAL; 1359 ds.depthBoundsTestEnable = VK_FALSE; 1360 ds.back.stencilFailOp = VK_STENCIL_OP_KEEP; 1361 ds.back.stencilPassOp = VK_STENCIL_OP_KEEP; 1362 ds.back.stencilCompareOp = VK_COMPARE_OP_ALWAYS; 1363 ds.stencilTestEnable = VK_FALSE; 1364 ds.front = ds.back; 1365 1366 memset(&ms, 0, sizeof(ms)); 1367 ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 1368 ms.pSampleMask = NULL; 1369 ms.rasterSamples = 1; 1370 1371 // Two stages: vs and fs 1372 pipeline.stageCount = 2; 1373 VkPipelineShaderStageCreateInfo shaderStages[2]; 1374 memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo)); 1375 1376 shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1377 shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; 1378 shaderStages[0].shader = demo_prepare_vs(demo); 1379 1380 shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1381 shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; 1382 shaderStages[1].shader = demo_prepare_fs(demo); 1383 1384 pipeline.pVertexInputState = &vi; 1385 pipeline.pInputAssemblyState = &ia; 1386 pipeline.pRasterState = &rs; 1387 pipeline.pColorBlendState = &cb; 1388 pipeline.pMultisampleState = &ms; 1389 pipeline.pViewportState = &vp; 1390 pipeline.pDepthStencilState = &ds; 1391 pipeline.pStages = shaderStages; 1392 pipeline.renderPass = demo->render_pass; 1393 pipeline.pDynamicState = &dynamicState; 1394 1395 memset(&pipelineCache, 0, sizeof(pipelineCache)); 1396 pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; 1397 1398 err = vkCreatePipelineCache(demo->device, &pipelineCache, &demo->pipelineCache); 1399 assert(!err); 1400 err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1, &pipeline, &demo->pipeline); 1401 assert(!err); 1402 1403 vkDestroyPipelineCache(demo->device, demo->pipelineCache); 1404 1405 for (uint32_t i = 0; i < pipeline.stageCount; i++) { 1406 vkDestroyShader(demo->device, shaderStages[i].shader); 1407 } 1408 vkDestroyShaderModule(demo->device, demo->frag_shader_module); 1409 vkDestroyShaderModule(demo->device, demo->vert_shader_module); 1410} 1411 1412static void demo_prepare_descriptor_pool(struct demo *demo) 1413{ 1414 const VkDescriptorTypeCount type_count = { 1415 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1416 .count = DEMO_TEXTURE_COUNT, 1417 }; 1418 const VkDescriptorPoolCreateInfo descriptor_pool = { 1419 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 1420 .pNext = NULL, 1421 .maxSets = 1, 1422 .count = 1, 1423 .pTypeCount = &type_count, 1424 }; 1425 VkResult U_ASSERT_ONLY err; 1426 1427 err = vkCreateDescriptorPool(demo->device, 1428 &descriptor_pool, &demo->desc_pool); 1429 assert(!err); 1430} 1431 1432static void demo_prepare_descriptor_set(struct demo *demo) 1433{ 1434 VkDescriptorImageInfo tex_descs[DEMO_TEXTURE_COUNT]; 1435 VkWriteDescriptorSet write; 1436 VkResult U_ASSERT_ONLY err; 1437 uint32_t i; 1438 1439 VkDescriptorSetAllocInfo alloc_info = { 1440 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOC_INFO, 1441 .pNext = NULL, 1442 .descriptorPool = demo->desc_pool, 1443 .count = 1, 1444 .pSetLayouts = &demo->desc_layout 1445 }; 1446 err = vkAllocDescriptorSets(demo->device, &alloc_info, &demo->desc_set); 1447 assert(!err); 1448 1449 memset(&tex_descs, 0, sizeof(tex_descs)); 1450 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1451 tex_descs[i].sampler = demo->textures[i].sampler; 1452 tex_descs[i].imageView = demo->textures[i].view; 1453 tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 1454 } 1455 1456 memset(&write, 0, sizeof(write)); 1457 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 1458 write.destSet = demo->desc_set; 1459 write.count = DEMO_TEXTURE_COUNT; 1460 write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 1461 write.pImageInfo = tex_descs; 1462 1463 vkUpdateDescriptorSets(demo->device, 1, &write, 0, NULL); 1464} 1465 1466static void demo_prepare_framebuffers(struct demo *demo) 1467{ 1468 VkImageView attachments[2]; 1469 attachments[1] = demo->depth.view; 1470 1471 const VkFramebufferCreateInfo fb_info = { 1472 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 1473 .pNext = NULL, 1474 .renderPass = demo->render_pass, 1475 .attachmentCount = 2, 1476 .pAttachments = attachments, 1477 .width = demo->width, 1478 .height = demo->height, 1479 .layers = 1, 1480 }; 1481 VkResult U_ASSERT_ONLY err; 1482 uint32_t i; 1483 1484 demo->framebuffers = (VkFramebuffer *) malloc(demo->swapchainImageCount * sizeof(VkFramebuffer)); 1485 assert(demo->framebuffers); 1486 1487 for (i = 0; i < demo->swapchainImageCount; i++) { 1488 attachments[0]= demo->buffers[i].view; 1489 err = vkCreateFramebuffer(demo->device, &fb_info, &demo->framebuffers[i]); 1490 assert(!err); 1491 } 1492} 1493 1494static void demo_prepare(struct demo *demo) 1495{ 1496 VkResult U_ASSERT_ONLY err; 1497 1498 const VkCmdPoolCreateInfo cmd_pool_info = { 1499 .sType = VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO, 1500 .pNext = NULL, 1501 .queueFamilyIndex = demo->graphics_queue_node_index, 1502 .flags = 0, 1503 }; 1504 err = vkCreateCommandPool(demo->device, &cmd_pool_info, &demo->cmd_pool); 1505 assert(!err); 1506 1507 const VkCmdBufferAllocInfo cmd = { 1508 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_ALLOC_INFO, 1509 .pNext = NULL, 1510 .cmdPool = demo->cmd_pool, 1511 .level = VK_CMD_BUFFER_LEVEL_PRIMARY, 1512 .count = 1, 1513 }; 1514 err = vkAllocCommandBuffers(demo->device, &cmd, &demo->draw_cmd); 1515 assert(!err); 1516 1517 demo_prepare_buffers(demo); 1518 demo_prepare_depth(demo); 1519 demo_prepare_textures(demo); 1520 demo_prepare_vertices(demo); 1521 demo_prepare_descriptor_layout(demo); 1522 demo_prepare_render_pass(demo); 1523 demo_prepare_pipeline(demo); 1524 1525 demo_prepare_descriptor_pool(demo); 1526 demo_prepare_descriptor_set(demo); 1527 1528 demo_prepare_framebuffers(demo); 1529 1530 demo->prepared = true; 1531} 1532 1533#ifdef _WIN32 1534static void demo_run(struct demo *demo) 1535{ 1536 if (!demo->prepared) 1537 return; 1538 demo_draw(demo); 1539 1540 if (demo->depthStencil > 0.99f) 1541 demo->depthIncrement = -0.001f; 1542 if (demo->depthStencil < 0.8f) 1543 demo->depthIncrement = 0.001f; 1544 1545 demo->depthStencil += demo->depthIncrement; 1546} 1547 1548// On MS-Windows, make this a global, so it's available to WndProc() 1549struct demo demo; 1550 1551// MS-Windows event handling function: 1552LRESULT CALLBACK WndProc(HWND hWnd, 1553 UINT uMsg, 1554 WPARAM wParam, 1555 LPARAM lParam) 1556{ 1557 char tmp_str[] = APP_LONG_NAME; 1558 1559 switch(uMsg) 1560 { 1561 case WM_CREATE: 1562 return 0; 1563 case WM_CLOSE: 1564 PostQuitMessage(0); 1565 return 0; 1566 case WM_PAINT: 1567 if (demo.prepared) { 1568 demo_run(&demo); 1569 break; 1570 } 1571 case WM_SIZE: 1572 demo.width = lParam & 0xffff; 1573 demo.height = lParam & 0xffff0000 >> 16; 1574 demo_resize(&demo); 1575 break; 1576 default: 1577 break; 1578 } 1579 return (DefWindowProc(hWnd, uMsg, wParam, lParam)); 1580} 1581 1582static void demo_create_window(struct demo *demo) 1583{ 1584 WNDCLASSEX win_class; 1585 1586 // Initialize the window class structure: 1587 win_class.cbSize = sizeof(WNDCLASSEX); 1588 win_class.style = CS_HREDRAW | CS_VREDRAW; 1589 win_class.lpfnWndProc = WndProc; 1590 win_class.cbClsExtra = 0; 1591 win_class.cbWndExtra = 0; 1592 win_class.hInstance = demo->connection; // hInstance 1593 win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); 1594 win_class.hCursor = LoadCursor(NULL, IDC_ARROW); 1595 win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 1596 win_class.lpszMenuName = NULL; 1597 win_class.lpszClassName = demo->name; 1598 win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO); 1599 // Register window class: 1600 if (!RegisterClassEx(&win_class)) { 1601 // It didn't work, so try to give a useful error: 1602 printf("Unexpected error trying to start the application!\n"); 1603 fflush(stdout); 1604 exit(1); 1605 } 1606 // Create window with the registered class: 1607 RECT wr = { 0, 0, demo->width, demo->height }; 1608 AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); 1609 demo->window = CreateWindowEx(0, 1610 demo->name, // class name 1611 demo->name, // app name 1612 WS_OVERLAPPEDWINDOW | // window style 1613 WS_VISIBLE | 1614 WS_SYSMENU, 1615 100,100, // x/y coords 1616 wr.right-wr.left, // width 1617 wr.bottom-wr.top, // height 1618 NULL, // handle to parent 1619 NULL, // handle to menu 1620 demo->connection, // hInstance 1621 NULL); // no extra parameters 1622 if (!demo->window) { 1623 // It didn't work, so try to give a useful error: 1624 printf("Cannot create a window in which to draw!\n"); 1625 fflush(stdout); 1626 exit(1); 1627 } 1628} 1629#else // _WIN32 1630 1631static void demo_handle_event(struct demo *demo, 1632 const xcb_generic_event_t *event) 1633{ 1634 switch (event->response_type & 0x7f) { 1635 case XCB_EXPOSE: 1636 demo_draw(demo); 1637 break; 1638 case XCB_CLIENT_MESSAGE: 1639 if((*(xcb_client_message_event_t*)event).data.data32[0] == 1640 (*demo->atom_wm_delete_window).atom) { 1641 demo->quit = true; 1642 } 1643 break; 1644 case XCB_KEY_RELEASE: 1645 { 1646 const xcb_key_release_event_t *key = 1647 (const xcb_key_release_event_t *) event; 1648 1649 if (key->detail == 0x9) 1650 demo->quit = true; 1651 } 1652 break; 1653 case XCB_DESTROY_NOTIFY: 1654 demo->quit = true; 1655 break; 1656 case XCB_CONFIGURE_NOTIFY: 1657 { 1658 const xcb_configure_notify_event_t *cfg = 1659 (const xcb_configure_notify_event_t *) event; 1660 if ((demo->width != cfg->width) || (demo->height != cfg->height)) { 1661 demo_resize(demo); 1662 } 1663 } 1664 break; 1665 default: 1666 break; 1667 } 1668} 1669 1670static void demo_run(struct demo *demo) 1671{ 1672 xcb_flush(demo->connection); 1673 1674 while (!demo->quit) { 1675 xcb_generic_event_t *event; 1676 1677 event = xcb_poll_for_event(demo->connection); 1678 if (event) { 1679 demo_handle_event(demo, event); 1680 free(event); 1681 } 1682 1683 demo_draw(demo); 1684 1685 if (demo->depthStencil > 0.99f) 1686 demo->depthIncrement = -0.001f; 1687 if (demo->depthStencil < 0.8f) 1688 demo->depthIncrement = 0.001f; 1689 1690 demo->depthStencil += demo->depthIncrement; 1691 1692 // Wait for work to finish before updating MVP. 1693 vkDeviceWaitIdle(demo->device); 1694 } 1695} 1696 1697static void demo_create_window(struct demo *demo) 1698{ 1699 uint32_t value_mask, value_list[32]; 1700 1701 demo->window = xcb_generate_id(demo->connection); 1702 1703 value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 1704 value_list[0] = demo->screen->black_pixel; 1705 value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | 1706 XCB_EVENT_MASK_EXPOSURE | 1707 XCB_EVENT_MASK_STRUCTURE_NOTIFY; 1708 1709 xcb_create_window(demo->connection, 1710 XCB_COPY_FROM_PARENT, 1711 demo->window, demo->screen->root, 1712 0, 0, demo->width, demo->height, 0, 1713 XCB_WINDOW_CLASS_INPUT_OUTPUT, 1714 demo->screen->root_visual, 1715 value_mask, value_list); 1716 1717 /* Magic code that will send notification when window is destroyed */ 1718 xcb_intern_atom_cookie_t cookie = xcb_intern_atom(demo->connection, 1, 12, 1719 "WM_PROTOCOLS"); 1720 xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(demo->connection, cookie, 0); 1721 1722 xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW"); 1723 demo->atom_wm_delete_window = xcb_intern_atom_reply(demo->connection, cookie2, 0); 1724 1725 xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, 1726 demo->window, (*reply).atom, 4, 32, 1, 1727 &(*demo->atom_wm_delete_window).atom); 1728 free(reply); 1729 1730 xcb_map_window(demo->connection, demo->window); 1731} 1732#endif // _WIN32 1733 1734/* 1735 * Return 1 (true) if all layer names specified in check_names 1736 * can be found in given layer properties. 1737 */ 1738static VkBool32 demo_check_layers(uint32_t check_count, char **check_names, 1739 uint32_t layer_count, VkLayerProperties *layers) 1740{ 1741 for (uint32_t i = 0; i < check_count; i++) { 1742 VkBool32 found = 0; 1743 for (uint32_t j = 0; j < layer_count; j++) { 1744 if (!strcmp(check_names[i], layers[j].layerName)) { 1745 found = 1; 1746 } 1747 } 1748 if (!found) { 1749 fprintf(stderr, "Cannot find layer: %s\n", check_names[i]); 1750 return 0; 1751 } 1752 } 1753 return 1; 1754} 1755 1756void* VKAPI myalloc( 1757 void* pUserData, 1758 size_t size, 1759 size_t alignment, 1760 VkSystemAllocType allocType) 1761{ 1762 return malloc(size); 1763} 1764void VKAPI myfree( 1765 void* pUserData, 1766 void* pMem) 1767{ 1768 free(pMem); 1769} 1770static void demo_init_vk(struct demo *demo) 1771{ 1772 VkResult err; 1773 char *extension_names[64]; 1774 char *layer_names[64]; 1775 VkExtensionProperties *instance_extensions; 1776 VkPhysicalDevice *physical_devices; 1777 VkLayerProperties *instance_layers; 1778 VkLayerProperties *device_layers; 1779 uint32_t instance_extension_count = 0; 1780 uint32_t instance_layer_count = 0; 1781 uint32_t enabled_extension_count = 0; 1782 uint32_t enabled_layer_count = 0; 1783 1784 char *instance_validation_layers[] = { 1785 "MemTracker", 1786 }; 1787 1788 char *device_validation_layers[] = { 1789 "MemTracker", 1790 }; 1791 1792 /* Look for validation layers */ 1793 VkBool32 validation_found = 0; 1794 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL); 1795 assert(!err); 1796 1797 instance_layers = malloc(sizeof(VkLayerProperties) * instance_layer_count); 1798 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, instance_layers); 1799 assert(!err); 1800 1801 if (demo->validate) { 1802 validation_found = demo_check_layers(ARRAY_SIZE(instance_validation_layers), instance_validation_layers, 1803 instance_layer_count, instance_layers); 1804 if (!validation_found) { 1805 ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find" 1806 "required validation layer.\n\n" 1807 "Please look at the Getting Started guide for additional " 1808 "information.\n", 1809 "vkCreateInstance Failure"); 1810 } 1811 enabled_layer_count = ARRAY_SIZE(instance_validation_layers); 1812 } 1813 1814 err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, NULL); 1815 assert(!err); 1816 1817 VkBool32 swapchainExtFound = 0; 1818 memset(extension_names, 0, sizeof(extension_names)); 1819 instance_extensions = malloc(sizeof(VkExtensionProperties) * instance_extension_count); 1820 err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, instance_extensions); 1821 assert(!err); 1822 for (uint32_t i = 0; i < instance_extension_count; i++) { 1823 if (!strcmp("VK_EXT_KHR_swapchain", instance_extensions[i].extName)) { 1824 swapchainExtFound = 1; 1825 extension_names[enabled_extension_count++] = "VK_EXT_KHR_swapchain"; 1826 } 1827 if (!strcmp(VK_DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extName)) { 1828 if (demo->validate) { 1829 extension_names[enabled_extension_count++] = VK_DEBUG_REPORT_EXTENSION_NAME; 1830 } 1831 } 1832 assert(enabled_extension_count < 64); 1833 } 1834 if (!swapchainExtFound) { 1835 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the " 1836 "\"VK_EXT_KHR_swapchain\" extension.\n\nDo you have a compatible " 1837 "Vulkan installable client driver (ICD) installed?\nPlease " 1838 "look at the Getting Started guide for additional " 1839 "information.\n", 1840 "vkCreateInstance Failure"); 1841 } 1842 const VkApplicationInfo app = { 1843 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 1844 .pNext = NULL, 1845 .pAppName = APP_SHORT_NAME, 1846 .appVersion = 0, 1847 .pEngineName = APP_SHORT_NAME, 1848 .engineVersion = 0, 1849 .apiVersion = VK_API_VERSION, 1850 }; 1851 VkAllocCallbacks cb = { 1852 .pUserData = NULL, 1853 .pfnAlloc = myalloc, 1854 .pfnFree = myfree, 1855 }; 1856 VkInstanceCreateInfo inst_info = { 1857 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 1858 .pNext = NULL, 1859 .pAppInfo = &app, 1860 .pAllocCb = &cb, 1861 .layerCount = enabled_layer_count, 1862 .ppEnabledLayerNames = (const char *const*) layer_names, 1863 .extensionCount = enabled_extension_count, 1864 .ppEnabledExtensionNames = (const char *const*) extension_names, 1865 }; 1866 float queue_priorities[1] = { 0.0 }; 1867 const VkDeviceQueueCreateInfo queue = { 1868 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 1869 .pNext = NULL, 1870 .queueFamilyIndex = 0, 1871 .queueCount = 1, 1872 .pQueuePriorities = queue_priorities 1873 }; 1874 uint32_t gpu_count; 1875 1876 err = vkCreateInstance(&inst_info, &demo->inst); 1877 if (err == VK_ERROR_INCOMPATIBLE_DRIVER) { 1878 ERR_EXIT("Cannot find a compatible Vulkan installable client driver " 1879 "(ICD).\n\nPlease look at the Getting Started guide for " 1880 "additional information.\n", 1881 "vkCreateInstance Failure"); 1882 } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) { 1883 ERR_EXIT("Cannot find a specified extension library" 1884 ".\nMake sure your layers path is set appropriately\n", 1885 "vkCreateInstance Failure"); 1886 } else if (err) { 1887 ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan " 1888 "installable client driver (ICD) installed?\nPlease look at " 1889 "the Getting Started guide for additional information.\n", 1890 "vkCreateInstance Failure"); 1891 } 1892 1893 free(instance_layers); 1894 free(instance_extensions); 1895 1896 /* Make initial call to query gpu_count, then second call for gpu info*/ 1897 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL); 1898 assert(!err && gpu_count > 0); 1899 physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count); 1900 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, physical_devices); 1901 assert(!err); 1902 /* For tri demo we just grab the first physical device */ 1903 demo->gpu = physical_devices[0]; 1904 free(physical_devices); 1905 1906 /* Look for validation layers */ 1907 validation_found = 0; 1908 enabled_layer_count = 0; 1909 uint32_t device_layer_count = 0; 1910 err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, NULL); 1911 assert(!err); 1912 1913 device_layers = malloc(sizeof(VkLayerProperties) * device_layer_count); 1914 err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, device_layers); 1915 assert(!err); 1916 1917 if (demo->validate) { 1918 validation_found = demo_check_layers(ARRAY_SIZE(device_validation_layers), device_validation_layers, 1919 device_layer_count, device_layers); 1920 if (!validation_found) { 1921 ERR_EXIT("vkEnumerateDeviceLayerProperties failed to find" 1922 "a required validation layer.\n\n" 1923 "Please look at the Getting Started guide for additional " 1924 "information.\n", 1925 "vkCreateDevice Failure"); 1926 } 1927 enabled_layer_count = ARRAY_SIZE(device_validation_layers); 1928 } 1929 1930 uint32_t device_extension_count = 0; 1931 VkExtensionProperties *device_extensions = NULL; 1932 err = vkEnumerateDeviceExtensionProperties( 1933 demo->gpu, NULL, &device_extension_count, NULL); 1934 assert(!err); 1935 1936 swapchainExtFound = 0; 1937 enabled_extension_count = 0; 1938 memset(extension_names, 0, sizeof(extension_names)); 1939 device_extensions = malloc(sizeof(VkExtensionProperties) * device_extension_count); 1940 err = vkEnumerateDeviceExtensionProperties( 1941 demo->gpu, NULL, &device_extension_count, device_extensions); 1942 assert(!err); 1943 1944 for (uint32_t i = 0; i < device_extension_count; i++) { 1945 if (!strcmp("VK_EXT_KHR_device_swapchain", device_extensions[i].extName)) { 1946 swapchainExtFound = 1; 1947 extension_names[enabled_extension_count++] = "VK_EXT_KHR_device_swapchain"; 1948 } 1949 assert(enabled_extension_count < 64); 1950 } 1951 if (!swapchainExtFound) { 1952 ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find the " 1953 "\"VK_EXT_KHR_device_swapchain\" extension.\n\nDo you have a compatible " 1954 "Vulkan installable client driver (ICD) installed?\nPlease " 1955 "look at the Getting Started guide for additional " 1956 "information.\n", 1957 "vkCreateInstance Failure"); 1958 } 1959 1960 VkDeviceCreateInfo device = { 1961 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 1962 .pNext = NULL, 1963 .requestedQueueCount = 1, 1964 .pRequestedQueues = &queue, 1965 .layerCount = enabled_layer_count, 1966 .ppEnabledLayerNames = (const char *const*) ((demo->validate) ? device_validation_layers : NULL), 1967 .extensionCount = enabled_extension_count, 1968 .ppEnabledExtensionNames = (const char *const*) extension_names, 1969 }; 1970 1971 if (demo->validate) { 1972 demo->dbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback) vkGetInstanceProcAddr(demo->inst, "vkDbgCreateMsgCallback"); 1973 if (!demo->dbgCreateMsgCallback) { 1974 ERR_EXIT("GetProcAddr: Unable to find vkDbgCreateMsgCallback\n", 1975 "vkGetProcAddr Failure"); 1976 } 1977 err = demo->dbgCreateMsgCallback( 1978 demo->inst, 1979 VK_DBG_REPORT_ERROR_BIT | VK_DBG_REPORT_WARN_BIT, 1980 dbgFunc, NULL, 1981 &demo->msg_callback); 1982 switch (err) { 1983 case VK_SUCCESS: 1984 break; 1985 case VK_ERROR_OUT_OF_HOST_MEMORY: 1986 ERR_EXIT("dbgCreateMsgCallback: out of host memory\n", 1987 "dbgCreateMsgCallback Failure"); 1988 break; 1989 default: 1990 ERR_EXIT("dbgCreateMsgCallback: unknown failure\n", 1991 "dbgCreateMsgCallback Failure"); 1992 break; 1993 } 1994 } 1995 1996 1997 err = vkCreateDevice(demo->gpu, &device, &demo->device); 1998 assert(!err); 1999 2000 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR); 2001 GET_DEVICE_PROC_ADDR(demo->device, GetSurfacePropertiesKHR); 2002 GET_DEVICE_PROC_ADDR(demo->device, GetSurfaceFormatsKHR); 2003 GET_DEVICE_PROC_ADDR(demo->device, GetSurfacePresentModesKHR); 2004 GET_DEVICE_PROC_ADDR(demo->device, CreateSwapchainKHR); 2005 GET_DEVICE_PROC_ADDR(demo->device, CreateSwapchainKHR); 2006 GET_DEVICE_PROC_ADDR(demo->device, DestroySwapchainKHR); 2007 GET_DEVICE_PROC_ADDR(demo->device, GetSwapchainImagesKHR); 2008 GET_DEVICE_PROC_ADDR(demo->device, AcquireNextImageKHR); 2009 GET_DEVICE_PROC_ADDR(demo->device, QueuePresentKHR); 2010 2011 vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props); 2012 2013 // Query with NULL data to get count 2014 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, NULL); 2015 2016 demo->queue_props = (VkQueueFamilyProperties *) malloc(demo->queue_count * sizeof(VkQueueFamilyProperties)); 2017 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, demo->queue_props); 2018 assert(demo->queue_count >= 1); 2019 2020 // Graphics queue and MemMgr queue can be separate. 2021 // TODO: Add support for separate queues, including synchronization, 2022 // and appropriate tracking for QueueSubmit 2023} 2024 2025static void demo_init_vk_swapchain(struct demo *demo) 2026{ 2027 VkResult U_ASSERT_ONLY err; 2028 uint32_t i; 2029 2030 // Construct the surface description: 2031 demo->surface_description.sType = VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_KHR; 2032 demo->surface_description.pNext = NULL; 2033#ifdef _WIN32 2034 demo->surface_description.platform = VK_PLATFORM_WIN32_KHR; 2035 demo->surface_description.pPlatformHandle = demo->connection; 2036 demo->surface_description.pPlatformWindow = demo->window; 2037#else // _WIN32 2038 demo->platform_handle_xcb.connection = demo->connection; 2039 demo->platform_handle_xcb.root = demo->screen->root; 2040 demo->surface_description.platform = VK_PLATFORM_XCB_KHR; 2041 demo->surface_description.pPlatformHandle = &demo->platform_handle_xcb; 2042 demo->surface_description.pPlatformWindow = &demo->window; 2043#endif // _WIN32 2044 2045 // Iterate over each queue to learn whether it supports presenting: 2046 VkBool32* supportsPresent = (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32)); 2047 for (i = 0; i < demo->queue_count; i++) { 2048 demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, 2049 (VkSurfaceDescriptionKHR *) &demo->surface_description, 2050 &supportsPresent[i]); 2051 } 2052 2053 // Search for a graphics and a present queue in the array of queue 2054 // families, try to find one that supports both 2055 uint32_t graphicsQueueNodeIndex = UINT32_MAX; 2056 uint32_t presentQueueNodeIndex = UINT32_MAX; 2057 for (i = 0; i < demo->queue_count; i++) { 2058 if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { 2059 if (graphicsQueueNodeIndex == UINT32_MAX) { 2060 graphicsQueueNodeIndex = i; 2061 } 2062 2063 if (supportsPresent[i] == VK_TRUE) { 2064 graphicsQueueNodeIndex = i; 2065 presentQueueNodeIndex = i; 2066 break; 2067 } 2068 } 2069 } 2070 if (presentQueueNodeIndex == UINT32_MAX) { 2071 // If didn't find a queue that supports both graphics and present, then 2072 // find a separate present queue. 2073 for (uint32_t i = 0; i < demo->queue_count; ++i) { 2074 if (supportsPresent[i] == VK_TRUE) { 2075 presentQueueNodeIndex = i; 2076 break; 2077 } 2078 } 2079 } 2080 free(supportsPresent); 2081 2082 // Generate error if could not find both a graphics and a present queue 2083 if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) { 2084 ERR_EXIT("Could not find a graphics and a present queue\n", 2085 "Swapchain Initialization Failure"); 2086 } 2087 2088 // TODO: Add support for separate queues, including presentation, 2089 // synchronization, and appropriate tracking for QueueSubmit 2090 // While it is possible for an application to use a separate graphics and a 2091 // present queues, this demo program assumes it is only using one: 2092 if (graphicsQueueNodeIndex != presentQueueNodeIndex) { 2093 ERR_EXIT("Could not find a common graphics and a present queue\n", 2094 "Swapchain Initialization Failure"); 2095 } 2096 2097 demo->graphics_queue_node_index = graphicsQueueNodeIndex; 2098 2099 vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 2100 0, &demo->queue); 2101 2102 // Get the list of VkFormat's that are supported: 2103 uint32_t formatCount; 2104 err = demo->fpGetSurfaceFormatsKHR(demo->device, 2105 (VkSurfaceDescriptionKHR *) &demo->surface_description, 2106 &formatCount, NULL); 2107 assert(!err); 2108 VkSurfaceFormatKHR *surfFormats = 2109 (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); 2110 err = demo->fpGetSurfaceFormatsKHR(demo->device, 2111 (VkSurfaceDescriptionKHR *) &demo->surface_description, 2112 &formatCount, surfFormats); 2113 assert(!err); 2114 // If the format list includes just one entry of VK_FORMAT_UNDEFINED, 2115 // the surface has no preferred format. Otherwise, at least one 2116 // supported format will be returned. 2117 if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) 2118 { 2119 demo->format = VK_FORMAT_B8G8R8A8_UNORM; 2120 } 2121 else 2122 { 2123 assert(formatCount >= 1); 2124 demo->format = surfFormats[0].format; 2125 } 2126 demo->color_space = surfFormats[0].colorSpace; 2127 2128 // Get Memory information and properties 2129 vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties); 2130} 2131 2132static void demo_init_connection(struct demo *demo) 2133{ 2134#ifndef _WIN32 2135 const xcb_setup_t *setup; 2136 xcb_screen_iterator_t iter; 2137 int scr; 2138 2139 demo->connection = xcb_connect(NULL, &scr); 2140 if (demo->connection == NULL) { 2141 printf("Cannot find a compatible Vulkan installable client driver " 2142 "(ICD).\nExiting ...\n"); 2143 fflush(stdout); 2144 exit(1); 2145 } 2146 2147 setup = xcb_get_setup(demo->connection); 2148 iter = xcb_setup_roots_iterator(setup); 2149 while (scr-- > 0) 2150 xcb_screen_next(&iter); 2151 2152 demo->screen = iter.data; 2153#endif // _WIN32 2154} 2155 2156#ifdef _WIN32 2157static void demo_init(struct demo *demo, HINSTANCE hInstance, LPSTR pCmdLine) 2158#else // _WIN32 2159static void demo_init(struct demo *demo, const int argc, const char *argv[]) 2160#endif // _WIN32 2161{ 2162 bool argv_error = false; 2163 2164 memset(demo, 0, sizeof(*demo)); 2165 2166#ifdef _WIN32 2167 demo->connection = hInstance; 2168 strncpy(demo->name, APP_SHORT_NAME, APP_NAME_STR_LEN); 2169 2170 if (strncmp(pCmdLine, "--use_staging", strlen("--use_staging")) == 0) 2171 demo->use_staging_buffer = true; 2172 else if (strncmp(pCmdLine, "--use_glsl", strlen("--use_glsl")) == 0) 2173 demo->use_glsl = true; 2174 else if (strlen(pCmdLine) != 0) { 2175 fprintf(stderr, "Do not recognize argument \"%s\".\n", pCmdLine); 2176 argv_error = true; 2177 } 2178#else // _WIN32 2179 for (int i = 0; i < argc; i++) { 2180 if (strncmp(argv[i], "--use_staging", strlen("--use_staging")) == 0) 2181 demo->use_staging_buffer = true; 2182 else if (strncmp(argv[i], "--use_glsl", strlen("--use_glsl")) == 0) 2183 demo->use_glsl = true; 2184 } 2185#endif // _WIN32 2186 if (argv_error) { 2187 fprintf(stderr, "Usage:\n %s [--use_staging]\n", APP_SHORT_NAME); 2188 fflush(stderr); 2189 exit(1); 2190 } 2191 2192 demo_init_connection(demo); 2193 demo_init_vk(demo); 2194 2195 demo->width = 300; 2196 demo->height = 300; 2197 demo->depthStencil = 1.0; 2198 demo->depthIncrement = -0.01f; 2199} 2200 2201static void demo_cleanup(struct demo *demo) 2202{ 2203 uint32_t i; 2204 2205 demo->prepared = false; 2206 2207 for (i = 0; i < demo->swapchainImageCount; i++) { 2208 vkDestroyFramebuffer(demo->device, demo->framebuffers[i]); 2209 } 2210 free(demo->framebuffers); 2211 vkDestroyDescriptorPool(demo->device, demo->desc_pool); 2212 2213 if (demo->setup_cmd) { 2214 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd); 2215 } 2216 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd); 2217 vkDestroyCommandPool(demo->device, demo->cmd_pool); 2218 2219 vkDestroyPipeline(demo->device, demo->pipeline); 2220 vkDestroyRenderPass(demo->device, demo->render_pass); 2221 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout); 2222 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout); 2223 2224 vkDestroyBuffer(demo->device, demo->vertices.buf); 2225 vkFreeMemory(demo->device, demo->vertices.mem); 2226 2227 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 2228 vkDestroyImageView(demo->device, demo->textures[i].view); 2229 vkDestroyImage(demo->device, demo->textures[i].image); 2230 vkFreeMemory(demo->device, demo->textures[i].mem); 2231 vkDestroySampler(demo->device, demo->textures[i].sampler); 2232 } 2233 2234 for (i = 0; i < demo->swapchainImageCount; i++) { 2235 vkDestroyImageView(demo->device, demo->buffers[i].view); 2236 } 2237 2238 vkDestroyImageView(demo->device, demo->depth.view); 2239 vkDestroyImage(demo->device, demo->depth.image); 2240 vkFreeMemory(demo->device, demo->depth.mem); 2241 2242 demo->fpDestroySwapchainKHR(demo->device, demo->swapchain); 2243 free(demo->buffers); 2244 2245 vkDestroyDevice(demo->device); 2246 vkDestroyInstance(demo->inst); 2247 2248 free(demo->queue_props); 2249 2250#ifndef _WIN32 2251 xcb_destroy_window(demo->connection, demo->window); 2252 xcb_disconnect(demo->connection); 2253 free(demo->atom_wm_delete_window); 2254#endif // _WIN32 2255} 2256 2257static void demo_resize(struct demo *demo) 2258{ 2259 uint32_t i; 2260 2261 // Don't react to resize until after first initialization. 2262 if (!demo->prepared) { 2263 return; 2264 } 2265 // In order to properly resize the window, we must re-create the swapchain 2266 // AND redo the command buffers, etc. 2267 // 2268 // First, perform part of the demo_cleanup() function: 2269 demo->prepared = false; 2270 2271 for (i = 0; i < demo->swapchainImageCount; i++) { 2272 vkDestroyFramebuffer(demo->device, demo->framebuffers[i]); 2273 } 2274 free(demo->framebuffers); 2275 vkDestroyDescriptorPool(demo->device, demo->desc_pool); 2276 2277 if (demo->setup_cmd) { 2278 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd); 2279 } 2280 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd); 2281 vkDestroyCommandPool(demo->device, demo->cmd_pool); 2282 2283 vkDestroyPipeline(demo->device, demo->pipeline); 2284 vkDestroyRenderPass(demo->device, demo->render_pass); 2285 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout); 2286 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout); 2287 2288 vkDestroyBuffer(demo->device, demo->vertices.buf); 2289 vkFreeMemory(demo->device, demo->vertices.mem); 2290 2291 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 2292 vkDestroyImageView(demo->device, demo->textures[i].view); 2293 vkDestroyImage(demo->device, demo->textures[i].image); 2294 vkFreeMemory(demo->device, demo->textures[i].mem); 2295 vkDestroySampler(demo->device, demo->textures[i].sampler); 2296 } 2297 2298 for (i = 0; i < demo->swapchainImageCount; i++) { 2299 vkDestroyImageView(demo->device, demo->buffers[i].view); 2300 } 2301 2302 vkDestroyImageView(demo->device, demo->depth.view); 2303 vkDestroyImage(demo->device, demo->depth.image); 2304 vkFreeMemory(demo->device, demo->depth.mem); 2305 2306 free(demo->buffers); 2307 2308 // Second, re-perform the demo_prepare() function, which will re-create the 2309 // swapchain: 2310 demo_prepare(demo); 2311} 2312 2313#ifdef _WIN32 2314int APIENTRY WinMain(HINSTANCE hInstance, 2315 HINSTANCE hPrevInstance, 2316 LPSTR pCmdLine, 2317 int nCmdShow) 2318{ 2319 MSG msg; // message 2320 bool done; // flag saying when app is complete 2321 2322 demo_init(&demo, hInstance, pCmdLine); 2323 demo_create_window(&demo); 2324 demo_init_vk_swapchain(&demo); 2325 2326 demo_prepare(&demo); 2327 2328 done = false; //initialize loop condition variable 2329 /* main message loop*/ 2330 while(!done) 2331 { 2332 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); 2333 if (msg.message == WM_QUIT) //check for a quit message 2334 { 2335 done = true; //if found, quit app 2336 } 2337 else 2338 { 2339 /* Translate and dispatch to event queue*/ 2340 TranslateMessage(&msg); 2341 DispatchMessage(&msg); 2342 } 2343 RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT); 2344 } 2345 2346 demo_cleanup(&demo); 2347 2348 return (int) msg.wParam; 2349} 2350#else // _WIN32 2351int main(const int argc, const char *argv[]) 2352{ 2353 struct demo demo; 2354 2355 demo_init(&demo, argc, argv); 2356 demo_create_window(&demo); 2357 demo_init_vk_swapchain(&demo); 2358 2359 demo_prepare(&demo); 2360 demo_run(&demo); 2361 2362 demo_cleanup(&demo); 2363 2364 return 0; 2365} 2366#endif // _WIN32 2367