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