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