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