ScrapExplorer - triangle-vulkan.c

Home / ext / glfw / tests Lines: 39 | Size: 81355 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 * Copyright (c) 2015-2016 The Khronos Group Inc. 3 * Copyright (c) 2015-2016 Valve Corporation 4 * Copyright (c) 2015-2016 LunarG, Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * Author: Chia-I Wu <[email protected]> 19 * Author: Cody Northrop <[email protected]> 20 * Author: Courtney Goeltzenleuchter <[email protected]> 21 * Author: Ian Elliott <[email protected]> 22 * Author: Jon Ashburn <[email protected]> 23 * Author: Piers Daniell <[email protected]> 24 * Author: Gwan-gyeong Mun <[email protected]> 25 * Porter: Camilla Löwy <[email protected]> 26 */ 27/* 28 * Draw a textured triangle with depth testing. This is written against Intel 29 * ICD. It does not do state transition nor object memory binding like it 30 * should. It also does no error checking. 31 */ 32 33#include <stdio.h> 34#include <stdlib.h> 35#include <string.h> 36#include <stdbool.h> 37#include <assert.h> 38#include <signal.h> 39 40#ifdef _WIN32 41#include <windows.h> 42#endif 43 44#define GLAD_VULKAN_IMPLEMENTATION 45#include <glad/vulkan.h> 46#define GLFW_INCLUDE_NONE 47#include <GLFW/glfw3.h> 48 49#define DEMO_TEXTURE_COUNT 1 50#define VERTEX_BUFFER_BIND_ID 0 51#define APP_SHORT_NAME "tri" 52#define APP_LONG_NAME "The Vulkan Triangle Demo Program" 53 54#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 55 56#if defined(NDEBUG) && defined(__GNUC__) 57#define U_ASSERT_ONLY __attribute__((unused)) 58#else 59#define U_ASSERT_ONLY 60#endif 61 62#define ERR_EXIT(err_msg, err_class) \ 63 do { \ 64 printf(err_msg); \ 65 fflush(stdout); \ 66 exit(1); \ 67 } while (0) 68 69static const uint32_t fragShaderCode[] = { 70 0x07230203,0x00010000,0x00080007,0x00000014,0x00000000,0x00020011,0x00000001,0x0006000b, 71 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, 72 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x00000011,0x00030010, 73 0x00000004,0x00000007,0x00030003,0x00000002,0x00000190,0x00090004,0x415f4c47,0x735f4252, 74 0x72617065,0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00090004,0x415f4c47, 75 0x735f4252,0x69646168,0x6c5f676e,0x75676e61,0x5f656761,0x70303234,0x006b6361,0x00040005, 76 0x00000004,0x6e69616d,0x00000000,0x00050005,0x00000009,0x61724675,0x6c6f4367,0x0000726f, 77 0x00030005,0x0000000d,0x00786574,0x00050005,0x00000011,0x63786574,0x64726f6f,0x00000000, 78 0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,0x00000022,0x00000000, 79 0x00040047,0x0000000d,0x00000021,0x00000000,0x00040047,0x00000011,0x0000001e,0x00000000, 80 0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020, 81 0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003,0x00000007, 82 0x0004003b,0x00000008,0x00000009,0x00000003,0x00090019,0x0000000a,0x00000006,0x00000001, 83 0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,0x0000000b,0x0000000a, 84 0x00040020,0x0000000c,0x00000000,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000000, 85 0x00040017,0x0000000f,0x00000006,0x00000002,0x00040020,0x00000010,0x00000001,0x0000000f, 86 0x0004003b,0x00000010,0x00000011,0x00000001,0x00050036,0x00000002,0x00000004,0x00000000, 87 0x00000003,0x000200f8,0x00000005,0x0004003d,0x0000000b,0x0000000e,0x0000000d,0x0004003d, 88 0x0000000f,0x00000012,0x00000011,0x00050057,0x00000007,0x00000013,0x0000000e,0x00000012, 89 0x0003003e,0x00000009,0x00000013,0x000100fd,0x00010038 90}; 91 92static const uint32_t vertShaderCode[] = { 93 0x07230203,0x00010000,0x00080007,0x00000018,0x00000000,0x00020011,0x00000001,0x0006000b, 94 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, 95 0x0009000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000b,0x00000010, 96 0x00000014,0x00030003,0x00000002,0x00000190,0x00090004,0x415f4c47,0x735f4252,0x72617065, 97 0x5f657461,0x64616873,0x6f5f7265,0x63656a62,0x00007374,0x00090004,0x415f4c47,0x735f4252, 98 0x69646168,0x6c5f676e,0x75676e61,0x5f656761,0x70303234,0x006b6361,0x00040005,0x00000004, 99 0x6e69616d,0x00000000,0x00050005,0x00000009,0x63786574,0x64726f6f,0x00000000,0x00040005, 100 0x0000000b,0x72747461,0x00000000,0x00060005,0x0000000e,0x505f6c67,0x65567265,0x78657472, 101 0x00000000,0x00060006,0x0000000e,0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00030005, 102 0x00000010,0x00000000,0x00030005,0x00000014,0x00736f70,0x00040047,0x00000009,0x0000001e, 103 0x00000000,0x00040047,0x0000000b,0x0000001e,0x00000001,0x00050048,0x0000000e,0x00000000, 104 0x0000000b,0x00000000,0x00030047,0x0000000e,0x00000002,0x00040047,0x00000014,0x0000001e, 105 0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006, 106 0x00000020,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000003, 107 0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040020,0x0000000a,0x00000001, 108 0x00000007,0x0004003b,0x0000000a,0x0000000b,0x00000001,0x00040017,0x0000000d,0x00000006, 109 0x00000004,0x0003001e,0x0000000e,0x0000000d,0x00040020,0x0000000f,0x00000003,0x0000000e, 110 0x0004003b,0x0000000f,0x00000010,0x00000003,0x00040015,0x00000011,0x00000020,0x00000001, 111 0x0004002b,0x00000011,0x00000012,0x00000000,0x00040020,0x00000013,0x00000001,0x0000000d, 112 0x0004003b,0x00000013,0x00000014,0x00000001,0x00040020,0x00000016,0x00000003,0x0000000d, 113 0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003d, 114 0x00000007,0x0000000c,0x0000000b,0x0003003e,0x00000009,0x0000000c,0x0004003d,0x0000000d, 115 0x00000015,0x00000014,0x00050041,0x00000016,0x00000017,0x00000010,0x00000012,0x0003003e, 116 0x00000017,0x00000015,0x000100fd,0x00010038 117}; 118 119struct texture_object { 120 VkSampler sampler; 121 122 VkImage image; 123 VkImageLayout imageLayout; 124 125 VkDeviceMemory mem; 126 VkImageView view; 127 int32_t tex_width, tex_height; 128}; 129 130static int validation_error = 0; 131 132VKAPI_ATTR VkBool32 VKAPI_CALL 133BreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, 134 uint64_t srcObject, size_t location, int32_t msgCode, 135 const char *pLayerPrefix, const char *pMsg, 136 void *pUserData) { 137#ifdef _WIN32 138 DebugBreak(); 139#else 140 raise(SIGTRAP); 141#endif 142 143 return false; 144} 145 146typedef struct { 147 VkImage image; 148 VkCommandBuffer cmd; 149 VkImageView view; 150} SwapchainBuffers; 151 152struct demo { 153 GLFWwindow* window; 154 VkSurfaceKHR surface; 155 bool use_staging_buffer; 156 157 VkInstance inst; 158 VkPhysicalDevice gpu; 159 VkDevice device; 160 VkQueue queue; 161 VkPhysicalDeviceProperties gpu_props; 162 VkPhysicalDeviceFeatures gpu_features; 163 VkQueueFamilyProperties *queue_props; 164 uint32_t graphics_queue_node_index; 165 166 uint32_t enabled_extension_count; 167 uint32_t enabled_layer_count; 168 const char *extension_names[64]; 169 const char *enabled_layers[64]; 170 171 int width, height; 172 VkFormat format; 173 VkColorSpaceKHR color_space; 174 175 uint32_t swapchainImageCount; 176 VkSwapchainKHR swapchain; 177 SwapchainBuffers *buffers; 178 179 VkCommandPool cmd_pool; 180 181 struct { 182 VkFormat format; 183 184 VkImage image; 185 VkDeviceMemory mem; 186 VkImageView view; 187 } depth; 188 189 struct texture_object textures[DEMO_TEXTURE_COUNT]; 190 191 struct { 192 VkBuffer buf; 193 VkDeviceMemory mem; 194 195 VkPipelineVertexInputStateCreateInfo vi; 196 VkVertexInputBindingDescription vi_bindings[1]; 197 VkVertexInputAttributeDescription vi_attrs[2]; 198 } vertices; 199 200 VkCommandBuffer setup_cmd; // Command Buffer for initialization commands 201 VkCommandBuffer draw_cmd; // Command Buffer for drawing commands 202 VkPipelineLayout pipeline_layout; 203 VkDescriptorSetLayout desc_layout; 204 VkPipelineCache pipelineCache; 205 VkRenderPass render_pass; 206 VkPipeline pipeline; 207 208 VkShaderModule vert_shader_module; 209 VkShaderModule frag_shader_module; 210 211 VkDescriptorPool desc_pool; 212 VkDescriptorSet desc_set; 213 214 VkFramebuffer *framebuffers; 215 216 VkPhysicalDeviceMemoryProperties memory_properties; 217 218 int32_t curFrame; 219 int32_t frameCount; 220 bool validate; 221 bool use_break; 222 VkDebugReportCallbackEXT msg_callback; 223 224 float depthStencil; 225 float depthIncrement; 226 227 uint32_t current_buffer; 228 uint32_t queue_count; 229}; 230 231VKAPI_ATTR VkBool32 VKAPI_CALL 232dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, 233 uint64_t srcObject, size_t location, int32_t msgCode, 234 const char *pLayerPrefix, const char *pMsg, void *pUserData) { 235 char *message = (char *)malloc(strlen(pMsg) + 100); 236 237 assert(message); 238 239 validation_error = 1; 240 241 if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { 242 sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, 243 pMsg); 244 } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { 245 sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, 246 pMsg); 247 } else { 248 return false; 249 } 250 251 printf("%s\n", message); 252 fflush(stdout); 253 free(message); 254 255 /* 256 * false indicates that layer should not bail-out of an 257 * API call that had validation failures. This may mean that the 258 * app dies inside the driver due to invalid parameter(s). 259 * That's what would happen without validation layers, so we'll 260 * keep that behavior here. 261 */ 262 return false; 263} 264 265// Forward declaration: 266static void demo_resize(struct demo *demo); 267 268static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits, 269 VkFlags requirements_mask, 270 uint32_t *typeIndex) { 271 uint32_t i; 272 // Search memtypes to find first index with those properties 273 for (i = 0; i < VK_MAX_MEMORY_TYPES; i++) { 274 if ((typeBits & 1) == 1) { 275 // Type is available, does it match user properties? 276 if ((demo->memory_properties.memoryTypes[i].propertyFlags & 277 requirements_mask) == requirements_mask) { 278 *typeIndex = i; 279 return true; 280 } 281 } 282 typeBits >>= 1; 283 } 284 // No memory types matched, return failure 285 return false; 286} 287 288static void demo_flush_init_cmd(struct demo *demo) { 289 VkResult U_ASSERT_ONLY err; 290 291 if (demo->setup_cmd == VK_NULL_HANDLE) 292 return; 293 294 err = vkEndCommandBuffer(demo->setup_cmd); 295 assert(!err); 296 297 const VkCommandBuffer cmd_bufs[] = {demo->setup_cmd}; 298 VkFence nullFence = {VK_NULL_HANDLE}; 299 VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 300 .pNext = NULL, 301 .waitSemaphoreCount = 0, 302 .pWaitSemaphores = NULL, 303 .pWaitDstStageMask = NULL, 304 .commandBufferCount = 1, 305 .pCommandBuffers = cmd_bufs, 306 .signalSemaphoreCount = 0, 307 .pSignalSemaphores = NULL}; 308 309 err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence); 310 assert(!err); 311 312 err = vkQueueWaitIdle(demo->queue); 313 assert(!err); 314 315 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, cmd_bufs); 316 demo->setup_cmd = VK_NULL_HANDLE; 317} 318 319static void demo_set_image_layout(struct demo *demo, VkImage image, 320 VkImageAspectFlags aspectMask, 321 VkImageLayout old_image_layout, 322 VkImageLayout new_image_layout, 323 VkAccessFlagBits srcAccessMask) { 324 325 VkResult U_ASSERT_ONLY err; 326 327 if (demo->setup_cmd == VK_NULL_HANDLE) { 328 const VkCommandBufferAllocateInfo cmd = { 329 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 330 .pNext = NULL, 331 .commandPool = demo->cmd_pool, 332 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 333 .commandBufferCount = 1, 334 }; 335 336 err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->setup_cmd); 337 assert(!err); 338 339 VkCommandBufferBeginInfo cmd_buf_info = { 340 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 341 .pNext = NULL, 342 .flags = 0, 343 .pInheritanceInfo = NULL, 344 }; 345 err = vkBeginCommandBuffer(demo->setup_cmd, &cmd_buf_info); 346 assert(!err); 347 } 348 349 VkImageMemoryBarrier image_memory_barrier = { 350 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 351 .pNext = NULL, 352 .srcAccessMask = srcAccessMask, 353 .dstAccessMask = 0, 354 .oldLayout = old_image_layout, 355 .newLayout = new_image_layout, 356 .image = image, 357 .subresourceRange = {aspectMask, 0, 1, 0, 1}}; 358 359 if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { 360 /* Make sure anything that was copying from this image has completed */ 361 image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; 362 } 363 364 if (new_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { 365 image_memory_barrier.dstAccessMask = 366 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 367 } 368 369 if (new_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { 370 image_memory_barrier.dstAccessMask = 371 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; 372 } 373 374 if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 375 /* Make sure any Copy or CPU writes to image are flushed */ 376 image_memory_barrier.dstAccessMask = 377 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; 378 } 379 380 VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier; 381 382 VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 383 VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 384 385 vkCmdPipelineBarrier(demo->setup_cmd, src_stages, dest_stages, 0, 0, NULL, 386 0, NULL, 1, pmemory_barrier); 387} 388 389static void demo_draw_build_cmd(struct demo *demo) { 390 const VkCommandBufferBeginInfo cmd_buf_info = { 391 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 392 .pNext = NULL, 393 .flags = 0, 394 .pInheritanceInfo = NULL, 395 }; 396 const VkClearValue clear_values[2] = { 397 [0] = {.color.float32 = {0.2f, 0.2f, 0.2f, 0.2f}}, 398 [1] = {.depthStencil = {demo->depthStencil, 0}}, 399 }; 400 const VkRenderPassBeginInfo rp_begin = { 401 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 402 .pNext = NULL, 403 .renderPass = demo->render_pass, 404 .framebuffer = demo->framebuffers[demo->current_buffer], 405 .renderArea.offset.x = 0, 406 .renderArea.offset.y = 0, 407 .renderArea.extent.width = demo->width, 408 .renderArea.extent.height = demo->height, 409 .clearValueCount = 2, 410 .pClearValues = clear_values, 411 }; 412 VkResult U_ASSERT_ONLY err; 413 414 err = vkBeginCommandBuffer(demo->draw_cmd, &cmd_buf_info); 415 assert(!err); 416 417 // We can use LAYOUT_UNDEFINED as a wildcard here because we don't care what 418 // happens to the previous contents of the image 419 VkImageMemoryBarrier image_memory_barrier = { 420 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 421 .pNext = NULL, 422 .srcAccessMask = 0, 423 .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 424 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, 425 .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 426 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 427 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 428 .image = demo->buffers[demo->current_buffer].image, 429 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; 430 431 vkCmdPipelineBarrier(demo->draw_cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 432 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, 433 NULL, 1, &image_memory_barrier); 434 vkCmdBeginRenderPass(demo->draw_cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); 435 vkCmdBindPipeline(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, 436 demo->pipeline); 437 vkCmdBindDescriptorSets(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, 438 demo->pipeline_layout, 0, 1, &demo->desc_set, 0, 439 NULL); 440 441 VkViewport viewport; 442 memset(&viewport, 0, sizeof(viewport)); 443 viewport.height = (float)demo->height; 444 viewport.width = (float)demo->width; 445 viewport.minDepth = (float)0.0f; 446 viewport.maxDepth = (float)1.0f; 447 vkCmdSetViewport(demo->draw_cmd, 0, 1, &viewport); 448 449 VkRect2D scissor; 450 memset(&scissor, 0, sizeof(scissor)); 451 scissor.extent.width = demo->width; 452 scissor.extent.height = demo->height; 453 scissor.offset.x = 0; 454 scissor.offset.y = 0; 455 vkCmdSetScissor(demo->draw_cmd, 0, 1, &scissor); 456 457 VkDeviceSize offsets[1] = {0}; 458 vkCmdBindVertexBuffers(demo->draw_cmd, VERTEX_BUFFER_BIND_ID, 1, 459 &demo->vertices.buf, offsets); 460 461 vkCmdDraw(demo->draw_cmd, 3, 1, 0, 0); 462 vkCmdEndRenderPass(demo->draw_cmd); 463 464 VkImageMemoryBarrier prePresentBarrier = { 465 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 466 .pNext = NULL, 467 .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 468 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, 469 .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 470 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 471 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 472 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 473 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; 474 475 prePresentBarrier.image = demo->buffers[demo->current_buffer].image; 476 VkImageMemoryBarrier *pmemory_barrier = &prePresentBarrier; 477 vkCmdPipelineBarrier(demo->draw_cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 478 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, 479 NULL, 1, pmemory_barrier); 480 481 err = vkEndCommandBuffer(demo->draw_cmd); 482 assert(!err); 483} 484 485static void demo_draw(struct demo *demo) { 486 VkResult U_ASSERT_ONLY err; 487 VkSemaphore imageAcquiredSemaphore, drawCompleteSemaphore; 488 VkSemaphoreCreateInfo semaphoreCreateInfo = { 489 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 490 .pNext = NULL, 491 .flags = 0, 492 }; 493 494 err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, 495 NULL, &imageAcquiredSemaphore); 496 assert(!err); 497 498 err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, 499 NULL, &drawCompleteSemaphore); 500 assert(!err); 501 502 // Get the index of the next available swapchain image: 503 err = vkAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX, 504 imageAcquiredSemaphore, 505 (VkFence)0, // TODO: Show use of fence 506 &demo->current_buffer); 507 if (err == VK_ERROR_OUT_OF_DATE_KHR) { 508 // demo->swapchain is out of date (e.g. the window was resized) and 509 // must be recreated: 510 demo_resize(demo); 511 demo_draw(demo); 512 vkDestroySemaphore(demo->device, imageAcquiredSemaphore, NULL); 513 vkDestroySemaphore(demo->device, drawCompleteSemaphore, NULL); 514 return; 515 } else if (err == VK_SUBOPTIMAL_KHR) { 516 // demo->swapchain is not as optimal as it could be, but the platform's 517 // presentation engine will still present the image correctly. 518 } else { 519 assert(!err); 520 } 521 522 demo_flush_init_cmd(demo); 523 524 // Wait for the present complete semaphore to be signaled to ensure 525 // that the image won't be rendered to until the presentation 526 // engine has fully released ownership to the application, and it is 527 // okay to render to the image. 528 529 demo_draw_build_cmd(demo); 530 VkFence nullFence = VK_NULL_HANDLE; 531 VkPipelineStageFlags pipe_stage_flags = 532 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; 533 VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 534 .pNext = NULL, 535 .waitSemaphoreCount = 1, 536 .pWaitSemaphores = &imageAcquiredSemaphore, 537 .pWaitDstStageMask = &pipe_stage_flags, 538 .commandBufferCount = 1, 539 .pCommandBuffers = &demo->draw_cmd, 540 .signalSemaphoreCount = 1, 541 .pSignalSemaphores = &drawCompleteSemaphore}; 542 543 err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence); 544 assert(!err); 545 546 VkPresentInfoKHR present = { 547 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 548 .pNext = NULL, 549 .waitSemaphoreCount = 1, 550 .pWaitSemaphores = &drawCompleteSemaphore, 551 .swapchainCount = 1, 552 .pSwapchains = &demo->swapchain, 553 .pImageIndices = &demo->current_buffer, 554 }; 555 556 err = vkQueuePresentKHR(demo->queue, &present); 557 if (err == VK_ERROR_OUT_OF_DATE_KHR) { 558 // demo->swapchain is out of date (e.g. the window was resized) and 559 // must be recreated: 560 demo_resize(demo); 561 } else if (err == VK_SUBOPTIMAL_KHR) { 562 // demo->swapchain is not as optimal as it could be, but the platform's 563 // presentation engine will still present the image correctly. 564 } else { 565 assert(!err); 566 } 567 568 err = vkQueueWaitIdle(demo->queue); 569 assert(err == VK_SUCCESS); 570 571 vkDestroySemaphore(demo->device, imageAcquiredSemaphore, NULL); 572 vkDestroySemaphore(demo->device, drawCompleteSemaphore, NULL); 573} 574 575static void demo_prepare_buffers(struct demo *demo) { 576 VkResult U_ASSERT_ONLY err; 577 VkSwapchainKHR oldSwapchain = demo->swapchain; 578 579 // Check the surface capabilities and formats 580 VkSurfaceCapabilitiesKHR surfCapabilities; 581 err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( 582 demo->gpu, demo->surface, &surfCapabilities); 583 assert(!err); 584 585 uint32_t presentModeCount; 586 err = vkGetPhysicalDeviceSurfacePresentModesKHR( 587 demo->gpu, demo->surface, &presentModeCount, NULL); 588 assert(!err); 589 VkPresentModeKHR *presentModes = 590 (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR)); 591 assert(presentModes); 592 err = vkGetPhysicalDeviceSurfacePresentModesKHR( 593 demo->gpu, demo->surface, &presentModeCount, presentModes); 594 assert(!err); 595 596 VkExtent2D swapchainExtent; 597 // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF. 598 if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) { 599 // If the surface size is undefined, the size is set to the size 600 // of the images requested, which must fit within the minimum and 601 // maximum values. 602 swapchainExtent.width = demo->width; 603 swapchainExtent.height = demo->height; 604 605 if (swapchainExtent.width < surfCapabilities.minImageExtent.width) { 606 swapchainExtent.width = surfCapabilities.minImageExtent.width; 607 } else if (swapchainExtent.width > surfCapabilities.maxImageExtent.width) { 608 swapchainExtent.width = surfCapabilities.maxImageExtent.width; 609 } 610 611 if (swapchainExtent.height < surfCapabilities.minImageExtent.height) { 612 swapchainExtent.height = surfCapabilities.minImageExtent.height; 613 } else if (swapchainExtent.height > surfCapabilities.maxImageExtent.height) { 614 swapchainExtent.height = surfCapabilities.maxImageExtent.height; 615 } 616 } else { 617 // If the surface size is defined, the swap chain size must match 618 swapchainExtent = surfCapabilities.currentExtent; 619 demo->width = surfCapabilities.currentExtent.width; 620 demo->height = surfCapabilities.currentExtent.height; 621 } 622 623 VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; 624 625 // Determine the number of VkImage's to use in the swap chain. 626 // Application desires to only acquire 1 image at a time (which is 627 // "surfCapabilities.minImageCount"). 628 uint32_t desiredNumOfSwapchainImages = surfCapabilities.minImageCount; 629 // If maxImageCount is 0, we can ask for as many images as we want; 630 // otherwise we're limited to maxImageCount 631 if ((surfCapabilities.maxImageCount > 0) && 632 (desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) { 633 // Application must settle for fewer images than desired: 634 desiredNumOfSwapchainImages = surfCapabilities.maxImageCount; 635 } 636 637 VkSurfaceTransformFlagsKHR preTransform; 638 if (surfCapabilities.supportedTransforms & 639 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { 640 preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 641 } else { 642 preTransform = surfCapabilities.currentTransform; 643 } 644 645 const VkSwapchainCreateInfoKHR swapchain = { 646 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 647 .pNext = NULL, 648 .surface = demo->surface, 649 .minImageCount = desiredNumOfSwapchainImages, 650 .imageFormat = demo->format, 651 .imageColorSpace = demo->color_space, 652 .imageExtent = 653 { 654 .width = swapchainExtent.width, .height = swapchainExtent.height, 655 }, 656 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 657 .preTransform = preTransform, 658 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, 659 .imageArrayLayers = 1, 660 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, 661 .queueFamilyIndexCount = 0, 662 .pQueueFamilyIndices = NULL, 663 .presentMode = swapchainPresentMode, 664 .oldSwapchain = oldSwapchain, 665 .clipped = true, 666 }; 667 uint32_t i; 668 669 err = vkCreateSwapchainKHR(demo->device, &swapchain, NULL, &demo->swapchain); 670 assert(!err); 671 672 // If we just re-created an existing swapchain, we should destroy the old 673 // swapchain at this point. 674 // Note: destroying the swapchain also cleans up all its associated 675 // presentable images once the platform is done with them. 676 if (oldSwapchain != VK_NULL_HANDLE) { 677 vkDestroySwapchainKHR(demo->device, oldSwapchain, NULL); 678 } 679 680 err = vkGetSwapchainImagesKHR(demo->device, demo->swapchain, 681 &demo->swapchainImageCount, NULL); 682 assert(!err); 683 684 VkImage *swapchainImages = 685 (VkImage *)malloc(demo->swapchainImageCount * sizeof(VkImage)); 686 assert(swapchainImages); 687 err = vkGetSwapchainImagesKHR(demo->device, demo->swapchain, 688 &demo->swapchainImageCount, 689 swapchainImages); 690 assert(!err); 691 692 demo->buffers = (SwapchainBuffers *)malloc(sizeof(SwapchainBuffers) * 693 demo->swapchainImageCount); 694 assert(demo->buffers); 695 696 for (i = 0; i < demo->swapchainImageCount; i++) { 697 VkImageViewCreateInfo color_attachment_view = { 698 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 699 .pNext = NULL, 700 .format = demo->format, 701 .components = 702 { 703 .r = VK_COMPONENT_SWIZZLE_R, 704 .g = VK_COMPONENT_SWIZZLE_G, 705 .b = VK_COMPONENT_SWIZZLE_B, 706 .a = VK_COMPONENT_SWIZZLE_A, 707 }, 708 .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 709 .baseMipLevel = 0, 710 .levelCount = 1, 711 .baseArrayLayer = 0, 712 .layerCount = 1}, 713 .viewType = VK_IMAGE_VIEW_TYPE_2D, 714 .flags = 0, 715 }; 716 717 demo->buffers[i].image = swapchainImages[i]; 718 719 color_attachment_view.image = demo->buffers[i].image; 720 721 err = vkCreateImageView(demo->device, &color_attachment_view, NULL, 722 &demo->buffers[i].view); 723 assert(!err); 724 } 725 726 demo->current_buffer = 0; 727 728 if (NULL != presentModes) { 729 free(presentModes); 730 } 731} 732 733static void demo_prepare_depth(struct demo *demo) { 734 const VkFormat depth_format = VK_FORMAT_D16_UNORM; 735 const VkImageCreateInfo image = { 736 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 737 .pNext = NULL, 738 .imageType = VK_IMAGE_TYPE_2D, 739 .format = depth_format, 740 .extent = {demo->width, demo->height, 1}, 741 .mipLevels = 1, 742 .arrayLayers = 1, 743 .samples = VK_SAMPLE_COUNT_1_BIT, 744 .tiling = VK_IMAGE_TILING_OPTIMAL, 745 .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 746 .flags = 0, 747 }; 748 VkMemoryAllocateInfo mem_alloc = { 749 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 750 .pNext = NULL, 751 .allocationSize = 0, 752 .memoryTypeIndex = 0, 753 }; 754 VkImageViewCreateInfo view = { 755 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 756 .pNext = NULL, 757 .image = VK_NULL_HANDLE, 758 .format = depth_format, 759 .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, 760 .baseMipLevel = 0, 761 .levelCount = 1, 762 .baseArrayLayer = 0, 763 .layerCount = 1}, 764 .flags = 0, 765 .viewType = VK_IMAGE_VIEW_TYPE_2D, 766 }; 767 768 VkMemoryRequirements mem_reqs; 769 VkResult U_ASSERT_ONLY err; 770 bool U_ASSERT_ONLY pass; 771 772 demo->depth.format = depth_format; 773 774 /* create image */ 775 err = vkCreateImage(demo->device, &image, NULL, &demo->depth.image); 776 assert(!err); 777 778 /* get memory requirements for this object */ 779 vkGetImageMemoryRequirements(demo->device, demo->depth.image, &mem_reqs); 780 781 /* select memory size and type */ 782 mem_alloc.allocationSize = mem_reqs.size; 783 pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, 784 0, /* No requirements */ 785 &mem_alloc.memoryTypeIndex); 786 assert(pass); 787 788 /* allocate memory */ 789 err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &demo->depth.mem); 790 assert(!err); 791 792 /* bind memory */ 793 err = 794 vkBindImageMemory(demo->device, demo->depth.image, demo->depth.mem, 0); 795 assert(!err); 796 797 demo_set_image_layout(demo, demo->depth.image, VK_IMAGE_ASPECT_DEPTH_BIT, 798 VK_IMAGE_LAYOUT_UNDEFINED, 799 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 800 0); 801 802 /* create image view */ 803 view.image = demo->depth.image; 804 err = vkCreateImageView(demo->device, &view, NULL, &demo->depth.view); 805 assert(!err); 806} 807 808static void 809demo_prepare_texture_image(struct demo *demo, const uint32_t *tex_colors, 810 struct texture_object *tex_obj, VkImageTiling tiling, 811 VkImageUsageFlags usage, VkFlags required_props) { 812 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; 813 const int32_t tex_width = 2; 814 const int32_t tex_height = 2; 815 VkResult U_ASSERT_ONLY err; 816 bool U_ASSERT_ONLY pass; 817 818 tex_obj->tex_width = tex_width; 819 tex_obj->tex_height = tex_height; 820 821 const VkImageCreateInfo image_create_info = { 822 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 823 .pNext = NULL, 824 .imageType = VK_IMAGE_TYPE_2D, 825 .format = tex_format, 826 .extent = {tex_width, tex_height, 1}, 827 .mipLevels = 1, 828 .arrayLayers = 1, 829 .samples = VK_SAMPLE_COUNT_1_BIT, 830 .tiling = tiling, 831 .usage = usage, 832 .flags = 0, 833 .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED 834 }; 835 VkMemoryAllocateInfo mem_alloc = { 836 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 837 .pNext = NULL, 838 .allocationSize = 0, 839 .memoryTypeIndex = 0, 840 }; 841 842 VkMemoryRequirements mem_reqs; 843 844 err = 845 vkCreateImage(demo->device, &image_create_info, NULL, &tex_obj->image); 846 assert(!err); 847 848 vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs); 849 850 mem_alloc.allocationSize = mem_reqs.size; 851 pass = 852 memory_type_from_properties(demo, mem_reqs.memoryTypeBits, 853 required_props, &mem_alloc.memoryTypeIndex); 854 assert(pass); 855 856 /* allocate memory */ 857 err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &tex_obj->mem); 858 assert(!err); 859 860 /* bind memory */ 861 err = vkBindImageMemory(demo->device, tex_obj->image, tex_obj->mem, 0); 862 assert(!err); 863 864 if (required_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { 865 const VkImageSubresource subres = { 866 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 867 .mipLevel = 0, 868 .arrayLayer = 0, 869 }; 870 VkSubresourceLayout layout; 871 void *data; 872 int32_t x, y; 873 874 vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres, 875 &layout); 876 877 err = vkMapMemory(demo->device, tex_obj->mem, 0, 878 mem_alloc.allocationSize, 0, &data); 879 assert(!err); 880 881 for (y = 0; y < tex_height; y++) { 882 uint32_t *row = (uint32_t *)((char *)data + layout.rowPitch * y); 883 for (x = 0; x < tex_width; x++) 884 row[x] = tex_colors[(x & 1) ^ (y & 1)]; 885 } 886 887 vkUnmapMemory(demo->device, tex_obj->mem); 888 } 889 890 tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 891 demo_set_image_layout(demo, tex_obj->image, VK_IMAGE_ASPECT_COLOR_BIT, 892 VK_IMAGE_LAYOUT_PREINITIALIZED, tex_obj->imageLayout, 893 VK_ACCESS_HOST_WRITE_BIT); 894 /* setting the image layout does not reference the actual memory so no need 895 * to add a mem ref */ 896} 897 898static void demo_destroy_texture_image(struct demo *demo, 899 struct texture_object *tex_obj) { 900 /* clean up staging resources */ 901 vkDestroyImage(demo->device, tex_obj->image, NULL); 902 vkFreeMemory(demo->device, tex_obj->mem, NULL); 903} 904 905static void demo_prepare_textures(struct demo *demo) { 906 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; 907 VkFormatProperties props; 908 const uint32_t tex_colors[DEMO_TEXTURE_COUNT][2] = { 909 {0xffff0000, 0xff00ff00}, 910 }; 911 uint32_t i; 912 VkResult U_ASSERT_ONLY err; 913 914 vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props); 915 916 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 917 if ((props.linearTilingFeatures & 918 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && 919 !demo->use_staging_buffer) { 920 /* Device can texture using linear textures */ 921 demo_prepare_texture_image( 922 demo, tex_colors[i], &demo->textures[i], VK_IMAGE_TILING_LINEAR, 923 VK_IMAGE_USAGE_SAMPLED_BIT, 924 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 925 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); 926 } else if (props.optimalTilingFeatures & 927 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { 928 /* Must use staging buffer to copy linear texture to optimized */ 929 struct texture_object staging_texture; 930 931 memset(&staging_texture, 0, sizeof(staging_texture)); 932 demo_prepare_texture_image( 933 demo, tex_colors[i], &staging_texture, VK_IMAGE_TILING_LINEAR, 934 VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 935 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 936 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); 937 938 demo_prepare_texture_image( 939 demo, tex_colors[i], &demo->textures[i], 940 VK_IMAGE_TILING_OPTIMAL, 941 (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT), 942 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); 943 944 demo_set_image_layout(demo, staging_texture.image, 945 VK_IMAGE_ASPECT_COLOR_BIT, 946 staging_texture.imageLayout, 947 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 948 0); 949 950 demo_set_image_layout(demo, demo->textures[i].image, 951 VK_IMAGE_ASPECT_COLOR_BIT, 952 demo->textures[i].imageLayout, 953 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 954 0); 955 956 VkImageCopy copy_region = { 957 .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, 958 .srcOffset = {0, 0, 0}, 959 .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, 960 .dstOffset = {0, 0, 0}, 961 .extent = {staging_texture.tex_width, 962 staging_texture.tex_height, 1}, 963 }; 964 vkCmdCopyImage( 965 demo->setup_cmd, staging_texture.image, 966 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, demo->textures[i].image, 967 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region); 968 969 demo_set_image_layout(demo, demo->textures[i].image, 970 VK_IMAGE_ASPECT_COLOR_BIT, 971 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 972 demo->textures[i].imageLayout, 973 0); 974 975 demo_flush_init_cmd(demo); 976 977 demo_destroy_texture_image(demo, &staging_texture); 978 } else { 979 /* Can't support VK_FORMAT_B8G8R8A8_UNORM !? */ 980 assert(!"No support for B8G8R8A8_UNORM as texture image format"); 981 } 982 983 const VkSamplerCreateInfo sampler = { 984 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 985 .pNext = NULL, 986 .magFilter = VK_FILTER_NEAREST, 987 .minFilter = VK_FILTER_NEAREST, 988 .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, 989 .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT, 990 .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT, 991 .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT, 992 .mipLodBias = 0.0f, 993 .anisotropyEnable = VK_FALSE, 994 .maxAnisotropy = 1, 995 .compareOp = VK_COMPARE_OP_NEVER, 996 .minLod = 0.0f, 997 .maxLod = 0.0f, 998 .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, 999 .unnormalizedCoordinates = VK_FALSE, 1000 }; 1001 VkImageViewCreateInfo view = { 1002 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 1003 .pNext = NULL, 1004 .image = VK_NULL_HANDLE, 1005 .viewType = VK_IMAGE_VIEW_TYPE_2D, 1006 .format = tex_format, 1007 .components = 1008 { 1009 VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, 1010 VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A, 1011 }, 1012 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}, 1013 .flags = 0, 1014 }; 1015 1016 /* create sampler */ 1017 err = vkCreateSampler(demo->device, &sampler, NULL, 1018 &demo->textures[i].sampler); 1019 assert(!err); 1020 1021 /* create image view */ 1022 view.image = demo->textures[i].image; 1023 err = vkCreateImageView(demo->device, &view, NULL, 1024 &demo->textures[i].view); 1025 assert(!err); 1026 } 1027} 1028 1029static void demo_prepare_vertices(struct demo *demo) { 1030 // clang-format off 1031 const float vb[3][5] = { 1032 /* position texcoord */ 1033 { -1.0f, -1.0f, 0.25f, 0.0f, 0.0f }, 1034 { 1.0f, -1.0f, 0.25f, 1.0f, 0.0f }, 1035 { 0.0f, 1.0f, 1.0f, 0.5f, 1.0f }, 1036 }; 1037 // clang-format on 1038 const VkBufferCreateInfo buf_info = { 1039 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 1040 .pNext = NULL, 1041 .size = sizeof(vb), 1042 .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 1043 .flags = 0, 1044 }; 1045 VkMemoryAllocateInfo mem_alloc = { 1046 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 1047 .pNext = NULL, 1048 .allocationSize = 0, 1049 .memoryTypeIndex = 0, 1050 }; 1051 VkMemoryRequirements mem_reqs; 1052 VkResult U_ASSERT_ONLY err; 1053 bool U_ASSERT_ONLY pass; 1054 void *data; 1055 1056 memset(&demo->vertices, 0, sizeof(demo->vertices)); 1057 1058 err = vkCreateBuffer(demo->device, &buf_info, NULL, &demo->vertices.buf); 1059 assert(!err); 1060 1061 vkGetBufferMemoryRequirements(demo->device, demo->vertices.buf, &mem_reqs); 1062 assert(!err); 1063 1064 mem_alloc.allocationSize = mem_reqs.size; 1065 pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, 1066 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 1067 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 1068 &mem_alloc.memoryTypeIndex); 1069 assert(pass); 1070 1071 err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &demo->vertices.mem); 1072 assert(!err); 1073 1074 err = vkMapMemory(demo->device, demo->vertices.mem, 0, 1075 mem_alloc.allocationSize, 0, &data); 1076 assert(!err); 1077 1078 memcpy(data, vb, sizeof(vb)); 1079 1080 vkUnmapMemory(demo->device, demo->vertices.mem); 1081 1082 err = vkBindBufferMemory(demo->device, demo->vertices.buf, 1083 demo->vertices.mem, 0); 1084 assert(!err); 1085 1086 demo->vertices.vi.sType = 1087 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 1088 demo->vertices.vi.pNext = NULL; 1089 demo->vertices.vi.vertexBindingDescriptionCount = 1; 1090 demo->vertices.vi.pVertexBindingDescriptions = demo->vertices.vi_bindings; 1091 demo->vertices.vi.vertexAttributeDescriptionCount = 2; 1092 demo->vertices.vi.pVertexAttributeDescriptions = demo->vertices.vi_attrs; 1093 1094 demo->vertices.vi_bindings[0].binding = VERTEX_BUFFER_BIND_ID; 1095 demo->vertices.vi_bindings[0].stride = sizeof(vb[0]); 1096 demo->vertices.vi_bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; 1097 1098 demo->vertices.vi_attrs[0].binding = VERTEX_BUFFER_BIND_ID; 1099 demo->vertices.vi_attrs[0].location = 0; 1100 demo->vertices.vi_attrs[0].format = VK_FORMAT_R32G32B32_SFLOAT; 1101 demo->vertices.vi_attrs[0].offset = 0; 1102 1103 demo->vertices.vi_attrs[1].binding = VERTEX_BUFFER_BIND_ID; 1104 demo->vertices.vi_attrs[1].location = 1; 1105 demo->vertices.vi_attrs[1].format = VK_FORMAT_R32G32_SFLOAT; 1106 demo->vertices.vi_attrs[1].offset = sizeof(float) * 3; 1107} 1108 1109static void demo_prepare_descriptor_layout(struct demo *demo) { 1110 const VkDescriptorSetLayoutBinding layout_binding = { 1111 .binding = 0, 1112 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1113 .descriptorCount = DEMO_TEXTURE_COUNT, 1114 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, 1115 .pImmutableSamplers = NULL, 1116 }; 1117 const VkDescriptorSetLayoutCreateInfo descriptor_layout = { 1118 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 1119 .pNext = NULL, 1120 .bindingCount = 1, 1121 .pBindings = &layout_binding, 1122 }; 1123 VkResult U_ASSERT_ONLY err; 1124 1125 err = vkCreateDescriptorSetLayout(demo->device, &descriptor_layout, NULL, 1126 &demo->desc_layout); 1127 assert(!err); 1128 1129 const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = { 1130 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 1131 .pNext = NULL, 1132 .setLayoutCount = 1, 1133 .pSetLayouts = &demo->desc_layout, 1134 }; 1135 1136 err = vkCreatePipelineLayout(demo->device, &pPipelineLayoutCreateInfo, NULL, 1137 &demo->pipeline_layout); 1138 assert(!err); 1139} 1140 1141static void demo_prepare_render_pass(struct demo *demo) { 1142 const VkAttachmentDescription attachments[2] = { 1143 [0] = 1144 { 1145 .format = demo->format, 1146 .samples = VK_SAMPLE_COUNT_1_BIT, 1147 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 1148 .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 1149 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 1150 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1151 .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1152 .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1153 }, 1154 [1] = 1155 { 1156 .format = demo->depth.format, 1157 .samples = VK_SAMPLE_COUNT_1_BIT, 1158 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 1159 .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1160 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 1161 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1162 .initialLayout = 1163 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1164 .finalLayout = 1165 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1166 }, 1167 }; 1168 const VkAttachmentReference color_reference = { 1169 .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1170 }; 1171 const VkAttachmentReference depth_reference = { 1172 .attachment = 1, 1173 .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1174 }; 1175 const VkSubpassDescription subpass = { 1176 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, 1177 .flags = 0, 1178 .inputAttachmentCount = 0, 1179 .pInputAttachments = NULL, 1180 .colorAttachmentCount = 1, 1181 .pColorAttachments = &color_reference, 1182 .pResolveAttachments = NULL, 1183 .pDepthStencilAttachment = &depth_reference, 1184 .preserveAttachmentCount = 0, 1185 .pPreserveAttachments = NULL, 1186 }; 1187 const VkRenderPassCreateInfo rp_info = { 1188 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 1189 .pNext = NULL, 1190 .attachmentCount = 2, 1191 .pAttachments = attachments, 1192 .subpassCount = 1, 1193 .pSubpasses = &subpass, 1194 .dependencyCount = 0, 1195 .pDependencies = NULL, 1196 }; 1197 VkResult U_ASSERT_ONLY err; 1198 1199 err = vkCreateRenderPass(demo->device, &rp_info, NULL, &demo->render_pass); 1200 assert(!err); 1201} 1202 1203static VkShaderModule 1204demo_prepare_shader_module(struct demo *demo, const void *code, size_t size) { 1205 VkShaderModuleCreateInfo moduleCreateInfo; 1206 VkShaderModule module; 1207 VkResult U_ASSERT_ONLY err; 1208 1209 moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 1210 moduleCreateInfo.pNext = NULL; 1211 1212 moduleCreateInfo.codeSize = size; 1213 moduleCreateInfo.pCode = code; 1214 moduleCreateInfo.flags = 0; 1215 err = vkCreateShaderModule(demo->device, &moduleCreateInfo, NULL, &module); 1216 assert(!err); 1217 1218 return module; 1219} 1220 1221static VkShaderModule demo_prepare_vs(struct demo *demo) { 1222 size_t size = sizeof(vertShaderCode); 1223 1224 demo->vert_shader_module = 1225 demo_prepare_shader_module(demo, vertShaderCode, size); 1226 1227 return demo->vert_shader_module; 1228} 1229 1230static VkShaderModule demo_prepare_fs(struct demo *demo) { 1231 size_t size = sizeof(fragShaderCode); 1232 1233 demo->frag_shader_module = 1234 demo_prepare_shader_module(demo, fragShaderCode, size); 1235 1236 return demo->frag_shader_module; 1237} 1238 1239static void demo_prepare_pipeline(struct demo *demo) { 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_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1)]; 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 rs.lineWidth = 1.0f; 1279 1280 memset(&cb, 0, sizeof(cb)); 1281 cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 1282 VkPipelineColorBlendAttachmentState att_state[1]; 1283 memset(att_state, 0, sizeof(att_state)); 1284 att_state[0].colorWriteMask = 0xf; 1285 att_state[0].blendEnable = VK_FALSE; 1286 cb.attachmentCount = 1; 1287 cb.pAttachments = att_state; 1288 1289 memset(&vp, 0, sizeof(vp)); 1290 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 1291 vp.viewportCount = 1; 1292 dynamicStateEnables[dynamicState.dynamicStateCount++] = 1293 VK_DYNAMIC_STATE_VIEWPORT; 1294 vp.scissorCount = 1; 1295 dynamicStateEnables[dynamicState.dynamicStateCount++] = 1296 VK_DYNAMIC_STATE_SCISSOR; 1297 1298 memset(&ds, 0, sizeof(ds)); 1299 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; 1300 ds.depthTestEnable = VK_TRUE; 1301 ds.depthWriteEnable = VK_TRUE; 1302 ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; 1303 ds.depthBoundsTestEnable = VK_FALSE; 1304 ds.back.failOp = VK_STENCIL_OP_KEEP; 1305 ds.back.passOp = VK_STENCIL_OP_KEEP; 1306 ds.back.compareOp = VK_COMPARE_OP_ALWAYS; 1307 ds.stencilTestEnable = VK_FALSE; 1308 ds.front = ds.back; 1309 1310 memset(&ms, 0, sizeof(ms)); 1311 ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 1312 ms.pSampleMask = NULL; 1313 ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; 1314 1315 // Two stages: vs and fs 1316 pipeline.stageCount = 2; 1317 VkPipelineShaderStageCreateInfo shaderStages[2]; 1318 memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo)); 1319 1320 shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1321 shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; 1322 shaderStages[0].module = demo_prepare_vs(demo); 1323 shaderStages[0].pName = "main"; 1324 1325 shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1326 shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; 1327 shaderStages[1].module = demo_prepare_fs(demo); 1328 shaderStages[1].pName = "main"; 1329 1330 pipeline.pVertexInputState = &vi; 1331 pipeline.pInputAssemblyState = &ia; 1332 pipeline.pRasterizationState = &rs; 1333 pipeline.pColorBlendState = &cb; 1334 pipeline.pMultisampleState = &ms; 1335 pipeline.pViewportState = &vp; 1336 pipeline.pDepthStencilState = &ds; 1337 pipeline.pStages = shaderStages; 1338 pipeline.renderPass = demo->render_pass; 1339 pipeline.pDynamicState = &dynamicState; 1340 1341 memset(&pipelineCache, 0, sizeof(pipelineCache)); 1342 pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; 1343 1344 err = vkCreatePipelineCache(demo->device, &pipelineCache, NULL, 1345 &demo->pipelineCache); 1346 assert(!err); 1347 err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1, 1348 &pipeline, NULL, &demo->pipeline); 1349 assert(!err); 1350 1351 vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL); 1352 1353 vkDestroyShaderModule(demo->device, demo->frag_shader_module, NULL); 1354 vkDestroyShaderModule(demo->device, demo->vert_shader_module, NULL); 1355} 1356 1357static void demo_prepare_descriptor_pool(struct demo *demo) { 1358 const VkDescriptorPoolSize type_count = { 1359 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1360 .descriptorCount = DEMO_TEXTURE_COUNT, 1361 }; 1362 const VkDescriptorPoolCreateInfo descriptor_pool = { 1363 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 1364 .pNext = NULL, 1365 .maxSets = 1, 1366 .poolSizeCount = 1, 1367 .pPoolSizes = &type_count, 1368 }; 1369 VkResult U_ASSERT_ONLY err; 1370 1371 err = vkCreateDescriptorPool(demo->device, &descriptor_pool, NULL, 1372 &demo->desc_pool); 1373 assert(!err); 1374} 1375 1376static void demo_prepare_descriptor_set(struct demo *demo) { 1377 VkDescriptorImageInfo tex_descs[DEMO_TEXTURE_COUNT]; 1378 VkWriteDescriptorSet write; 1379 VkResult U_ASSERT_ONLY err; 1380 uint32_t i; 1381 1382 VkDescriptorSetAllocateInfo alloc_info = { 1383 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 1384 .pNext = NULL, 1385 .descriptorPool = demo->desc_pool, 1386 .descriptorSetCount = 1, 1387 .pSetLayouts = &demo->desc_layout}; 1388 err = vkAllocateDescriptorSets(demo->device, &alloc_info, &demo->desc_set); 1389 assert(!err); 1390 1391 memset(&tex_descs, 0, sizeof(tex_descs)); 1392 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1393 tex_descs[i].sampler = demo->textures[i].sampler; 1394 tex_descs[i].imageView = demo->textures[i].view; 1395 tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 1396 } 1397 1398 memset(&write, 0, sizeof(write)); 1399 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 1400 write.dstSet = demo->desc_set; 1401 write.descriptorCount = DEMO_TEXTURE_COUNT; 1402 write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 1403 write.pImageInfo = tex_descs; 1404 1405 vkUpdateDescriptorSets(demo->device, 1, &write, 0, NULL); 1406} 1407 1408static void demo_prepare_framebuffers(struct demo *demo) { 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 * 1426 sizeof(VkFramebuffer)); 1427 assert(demo->framebuffers); 1428 1429 for (i = 0; i < demo->swapchainImageCount; i++) { 1430 attachments[0] = demo->buffers[i].view; 1431 err = vkCreateFramebuffer(demo->device, &fb_info, NULL, 1432 &demo->framebuffers[i]); 1433 assert(!err); 1434 } 1435} 1436 1437static void demo_prepare(struct demo *demo) { 1438 VkResult U_ASSERT_ONLY err; 1439 1440 const VkCommandPoolCreateInfo cmd_pool_info = { 1441 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 1442 .pNext = NULL, 1443 .queueFamilyIndex = demo->graphics_queue_node_index, 1444 .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, 1445 }; 1446 err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL, 1447 &demo->cmd_pool); 1448 assert(!err); 1449 1450 const VkCommandBufferAllocateInfo cmd = { 1451 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 1452 .pNext = NULL, 1453 .commandPool = demo->cmd_pool, 1454 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1455 .commandBufferCount = 1, 1456 }; 1457 err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->draw_cmd); 1458 assert(!err); 1459 1460 demo_prepare_buffers(demo); 1461 demo_prepare_depth(demo); 1462 demo_prepare_textures(demo); 1463 demo_prepare_vertices(demo); 1464 demo_prepare_descriptor_layout(demo); 1465 demo_prepare_render_pass(demo); 1466 demo_prepare_pipeline(demo); 1467 1468 demo_prepare_descriptor_pool(demo); 1469 demo_prepare_descriptor_set(demo); 1470 1471 demo_prepare_framebuffers(demo); 1472} 1473 1474static void demo_error_callback(int error, const char* description) { 1475 printf("GLFW error: %s\n", description); 1476 fflush(stdout); 1477} 1478 1479static void demo_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { 1480 if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) 1481 glfwSetWindowShouldClose(window, GLFW_TRUE); 1482} 1483 1484static void demo_refresh_callback(GLFWwindow* window) { 1485 struct demo* demo = glfwGetWindowUserPointer(window); 1486 demo_draw(demo); 1487} 1488 1489static void demo_resize_callback(GLFWwindow* window, int width, int height) { 1490 struct demo* demo = glfwGetWindowUserPointer(window); 1491 demo->width = width; 1492 demo->height = height; 1493 demo_resize(demo); 1494} 1495 1496static void demo_run(struct demo *demo) { 1497 while (!glfwWindowShouldClose(demo->window)) { 1498 glfwPollEvents(); 1499 1500 demo_draw(demo); 1501 1502 if (demo->depthStencil > 0.99f) 1503 demo->depthIncrement = -0.001f; 1504 if (demo->depthStencil < 0.8f) 1505 demo->depthIncrement = 0.001f; 1506 1507 demo->depthStencil += demo->depthIncrement; 1508 1509 // Wait for work to finish before updating MVP. 1510 vkDeviceWaitIdle(demo->device); 1511 demo->curFrame++; 1512 if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) 1513 glfwSetWindowShouldClose(demo->window, GLFW_TRUE); 1514 } 1515} 1516 1517static void demo_create_window(struct demo *demo) { 1518 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); 1519 1520 demo->window = glfwCreateWindow(demo->width, 1521 demo->height, 1522 APP_LONG_NAME, 1523 NULL, 1524 NULL); 1525 if (!demo->window) { 1526 // It didn't work, so try to give a useful error: 1527 printf("Cannot create a window in which to draw!\n"); 1528 fflush(stdout); 1529 exit(1); 1530 } 1531 1532 glfwSetWindowUserPointer(demo->window, demo); 1533 glfwSetWindowRefreshCallback(demo->window, demo_refresh_callback); 1534 glfwSetFramebufferSizeCallback(demo->window, demo_resize_callback); 1535 glfwSetKeyCallback(demo->window, demo_key_callback); 1536} 1537 1538/* 1539 * Return 1 (true) if all layer names specified in check_names 1540 * can be found in given layer properties. 1541 */ 1542static VkBool32 demo_check_layers(uint32_t check_count, const char **check_names, 1543 uint32_t layer_count, 1544 VkLayerProperties *layers) { 1545 uint32_t i, j; 1546 for (i = 0; i < check_count; i++) { 1547 VkBool32 found = 0; 1548 for (j = 0; j < layer_count; j++) { 1549 if (!strcmp(check_names[i], layers[j].layerName)) { 1550 found = 1; 1551 break; 1552 } 1553 } 1554 if (!found) { 1555 fprintf(stderr, "Cannot find layer: %s\n", check_names[i]); 1556 return 0; 1557 } 1558 } 1559 return 1; 1560} 1561 1562static void demo_init_vk(struct demo *demo) { 1563 VkResult err; 1564 VkBool32 portability_enumeration = VK_FALSE; 1565 uint32_t i = 0; 1566 uint32_t required_extension_count = 0; 1567 uint32_t instance_extension_count = 0; 1568 uint32_t instance_layer_count = 0; 1569 uint32_t validation_layer_count = 0; 1570 const char **required_extensions = NULL; 1571 const char **instance_validation_layers = NULL; 1572 demo->enabled_extension_count = 0; 1573 demo->enabled_layer_count = 0; 1574 1575 char *instance_validation_layers_alt1[] = { 1576 "VK_LAYER_LUNARG_standard_validation" 1577 }; 1578 1579 char *instance_validation_layers_alt2[] = { 1580 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", 1581 "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_image", 1582 "VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain", 1583 "VK_LAYER_GOOGLE_unique_objects" 1584 }; 1585 1586 /* Look for validation layers */ 1587 VkBool32 validation_found = 0; 1588 if (demo->validate) { 1589 1590 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL); 1591 assert(!err); 1592 1593 instance_validation_layers = (const char**) instance_validation_layers_alt1; 1594 if (instance_layer_count > 0) { 1595 VkLayerProperties *instance_layers = 1596 malloc(sizeof (VkLayerProperties) * instance_layer_count); 1597 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, 1598 instance_layers); 1599 assert(!err); 1600 1601 1602 validation_found = demo_check_layers( 1603 ARRAY_SIZE(instance_validation_layers_alt1), 1604 instance_validation_layers, instance_layer_count, 1605 instance_layers); 1606 if (validation_found) { 1607 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1); 1608 demo->enabled_layers[0] = "VK_LAYER_LUNARG_standard_validation"; 1609 validation_layer_count = 1; 1610 } else { 1611 // use alternative set of validation layers 1612 instance_validation_layers = 1613 (const char**) instance_validation_layers_alt2; 1614 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2); 1615 validation_found = demo_check_layers( 1616 ARRAY_SIZE(instance_validation_layers_alt2), 1617 instance_validation_layers, instance_layer_count, 1618 instance_layers); 1619 validation_layer_count = 1620 ARRAY_SIZE(instance_validation_layers_alt2); 1621 for (i = 0; i < validation_layer_count; i++) { 1622 demo->enabled_layers[i] = instance_validation_layers[i]; 1623 } 1624 } 1625 free(instance_layers); 1626 } 1627 1628 if (!validation_found) { 1629 ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find " 1630 "required validation layer.\n\n" 1631 "Please look at the Getting Started guide for additional " 1632 "information.\n", 1633 "vkCreateInstance Failure"); 1634 } 1635 } 1636 1637 /* Look for instance extensions */ 1638 required_extensions = glfwGetRequiredInstanceExtensions(&required_extension_count); 1639 if (!required_extensions) { 1640 ERR_EXIT("glfwGetRequiredInstanceExtensions failed to find the " 1641 "platform surface extensions.\n\nDo you have a compatible " 1642 "Vulkan installable client driver (ICD) installed?\nPlease " 1643 "look at the Getting Started guide for additional " 1644 "information.\n", 1645 "vkCreateInstance Failure"); 1646 } 1647 1648 for (i = 0; i < required_extension_count; i++) { 1649 demo->extension_names[demo->enabled_extension_count++] = required_extensions[i]; 1650 assert(demo->enabled_extension_count < 64); 1651 } 1652 1653 err = vkEnumerateInstanceExtensionProperties( 1654 NULL, &instance_extension_count, NULL); 1655 assert(!err); 1656 1657 if (instance_extension_count > 0) { 1658 VkExtensionProperties *instance_extensions = 1659 malloc(sizeof(VkExtensionProperties) * instance_extension_count); 1660 err = vkEnumerateInstanceExtensionProperties( 1661 NULL, &instance_extension_count, instance_extensions); 1662 assert(!err); 1663 for (i = 0; i < instance_extension_count; i++) { 1664 if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, 1665 instance_extensions[i].extensionName)) { 1666 if (demo->validate) { 1667 demo->extension_names[demo->enabled_extension_count++] = 1668 VK_EXT_DEBUG_REPORT_EXTENSION_NAME; 1669 } 1670 } 1671 assert(demo->enabled_extension_count < 64); 1672 if (!strcmp(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, 1673 instance_extensions[i].extensionName)) { 1674 demo->extension_names[demo->enabled_extension_count++] = 1675 VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME; 1676 portability_enumeration = VK_TRUE; 1677 } 1678 assert(demo->enabled_extension_count < 64); 1679 } 1680 1681 free(instance_extensions); 1682 } 1683 1684 const VkApplicationInfo app = { 1685 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 1686 .pNext = NULL, 1687 .pApplicationName = APP_SHORT_NAME, 1688 .applicationVersion = 0, 1689 .pEngineName = APP_SHORT_NAME, 1690 .engineVersion = 0, 1691 .apiVersion = VK_API_VERSION_1_0, 1692 }; 1693 VkInstanceCreateInfo inst_info = { 1694 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 1695 .pNext = NULL, 1696 .pApplicationInfo = &app, 1697 .enabledLayerCount = demo->enabled_layer_count, 1698 .ppEnabledLayerNames = (const char *const *)instance_validation_layers, 1699 .enabledExtensionCount = demo->enabled_extension_count, 1700 .ppEnabledExtensionNames = (const char *const *)demo->extension_names, 1701 }; 1702 1703 if (portability_enumeration) 1704 inst_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; 1705 1706 uint32_t gpu_count; 1707 1708 err = vkCreateInstance(&inst_info, NULL, &demo->inst); 1709 if (err == VK_ERROR_INCOMPATIBLE_DRIVER) { 1710 ERR_EXIT("Cannot find a compatible Vulkan installable client driver " 1711 "(ICD).\n\nPlease look at the Getting Started guide for " 1712 "additional information.\n", 1713 "vkCreateInstance Failure"); 1714 } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) { 1715 ERR_EXIT("Cannot find a specified extension library" 1716 ".\nMake sure your layers path is set appropriately\n", 1717 "vkCreateInstance Failure"); 1718 } else if (err) { 1719 ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan " 1720 "installable client driver (ICD) installed?\nPlease look at " 1721 "the Getting Started guide for additional information.\n", 1722 "vkCreateInstance Failure"); 1723 } 1724 1725 gladLoadVulkanUserPtr(NULL, (GLADuserptrloadfunc) glfwGetInstanceProcAddress, demo->inst); 1726 1727 /* Make initial call to query gpu_count, then second call for gpu info*/ 1728 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL); 1729 assert(!err && gpu_count > 0); 1730 1731 if (gpu_count > 0) { 1732 VkPhysicalDevice *physical_devices = 1733 malloc(sizeof(VkPhysicalDevice) * gpu_count); 1734 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, 1735 physical_devices); 1736 assert(!err); 1737 /* For tri demo we just grab the first physical device */ 1738 demo->gpu = physical_devices[0]; 1739 free(physical_devices); 1740 } else { 1741 ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible devices." 1742 "\n\nDo you have a compatible Vulkan installable client" 1743 " driver (ICD) installed?\nPlease look at the Getting Started" 1744 " guide for additional information.\n", 1745 "vkEnumeratePhysicalDevices Failure"); 1746 } 1747 1748 gladLoadVulkanUserPtr(demo->gpu, (GLADuserptrloadfunc) glfwGetInstanceProcAddress, demo->inst); 1749 1750 /* Look for device extensions */ 1751 uint32_t device_extension_count = 0; 1752 VkBool32 swapchainExtFound = 0; 1753 demo->enabled_extension_count = 0; 1754 1755 err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL, 1756 &device_extension_count, NULL); 1757 assert(!err); 1758 1759 if (device_extension_count > 0) { 1760 VkExtensionProperties *device_extensions = 1761 malloc(sizeof(VkExtensionProperties) * device_extension_count); 1762 err = vkEnumerateDeviceExtensionProperties( 1763 demo->gpu, NULL, &device_extension_count, device_extensions); 1764 assert(!err); 1765 1766 for (i = 0; i < device_extension_count; i++) { 1767 if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 1768 device_extensions[i].extensionName)) { 1769 swapchainExtFound = 1; 1770 demo->extension_names[demo->enabled_extension_count++] = 1771 VK_KHR_SWAPCHAIN_EXTENSION_NAME; 1772 } 1773 assert(demo->enabled_extension_count < 64); 1774 } 1775 1776 free(device_extensions); 1777 } 1778 1779 if (!swapchainExtFound) { 1780 ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find " 1781 "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME 1782 " extension.\n\nDo you have a compatible " 1783 "Vulkan installable client driver (ICD) installed?\nPlease " 1784 "look at the Getting Started guide for additional " 1785 "information.\n", 1786 "vkCreateInstance Failure"); 1787 } 1788 1789 if (demo->validate) { 1790 VkDebugReportCallbackCreateInfoEXT dbgCreateInfo; 1791 dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; 1792 dbgCreateInfo.flags = 1793 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; 1794 dbgCreateInfo.pfnCallback = demo->use_break ? BreakCallback : dbgFunc; 1795 dbgCreateInfo.pUserData = demo; 1796 dbgCreateInfo.pNext = NULL; 1797 err = vkCreateDebugReportCallbackEXT(demo->inst, &dbgCreateInfo, NULL, 1798 &demo->msg_callback); 1799 switch (err) { 1800 case VK_SUCCESS: 1801 break; 1802 case VK_ERROR_OUT_OF_HOST_MEMORY: 1803 ERR_EXIT("CreateDebugReportCallback: out of host memory\n", 1804 "CreateDebugReportCallback Failure"); 1805 break; 1806 default: 1807 ERR_EXIT("CreateDebugReportCallback: unknown failure\n", 1808 "CreateDebugReportCallback Failure"); 1809 break; 1810 } 1811 } 1812 1813 vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props); 1814 1815 // Query with NULL data to get count 1816 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, 1817 NULL); 1818 1819 demo->queue_props = (VkQueueFamilyProperties *)malloc( 1820 demo->queue_count * sizeof(VkQueueFamilyProperties)); 1821 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, 1822 demo->queue_props); 1823 assert(demo->queue_count >= 1); 1824 1825 vkGetPhysicalDeviceFeatures(demo->gpu, &demo->gpu_features); 1826 1827 // Graphics queue and MemMgr queue can be separate. 1828 // TODO: Add support for separate queues, including synchronization, 1829 // and appropriate tracking for QueueSubmit 1830} 1831 1832static void demo_init_device(struct demo *demo) { 1833 VkResult U_ASSERT_ONLY err; 1834 1835 float queue_priorities[1] = {0.0}; 1836 const VkDeviceQueueCreateInfo queue = { 1837 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 1838 .pNext = NULL, 1839 .queueFamilyIndex = demo->graphics_queue_node_index, 1840 .queueCount = 1, 1841 .pQueuePriorities = queue_priorities}; 1842 1843 1844 VkPhysicalDeviceFeatures features; 1845 memset(&features, 0, sizeof(features)); 1846 if (demo->gpu_features.shaderClipDistance) { 1847 features.shaderClipDistance = VK_TRUE; 1848 } 1849 1850 VkDeviceCreateInfo device = { 1851 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 1852 .pNext = NULL, 1853 .queueCreateInfoCount = 1, 1854 .pQueueCreateInfos = &queue, 1855 .enabledLayerCount = 0, 1856 .ppEnabledLayerNames = NULL, 1857 .enabledExtensionCount = demo->enabled_extension_count, 1858 .ppEnabledExtensionNames = (const char *const *)demo->extension_names, 1859 .pEnabledFeatures = &features, 1860 }; 1861 1862 err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device); 1863 assert(!err); 1864} 1865 1866static void demo_init_vk_swapchain(struct demo *demo) { 1867 VkResult U_ASSERT_ONLY err; 1868 uint32_t i; 1869 1870 // Create a WSI surface for the window: 1871 glfwCreateWindowSurface(demo->inst, demo->window, NULL, &demo->surface); 1872 1873 // Iterate over each queue to learn whether it supports presenting: 1874 VkBool32 *supportsPresent = 1875 (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32)); 1876 for (i = 0; i < demo->queue_count; i++) { 1877 vkGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface, 1878 &supportsPresent[i]); 1879 } 1880 1881 // Search for a graphics and a present queue in the array of queue 1882 // families, try to find one that supports both 1883 uint32_t graphicsQueueNodeIndex = UINT32_MAX; 1884 uint32_t presentQueueNodeIndex = UINT32_MAX; 1885 for (i = 0; i < demo->queue_count; i++) { 1886 if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { 1887 if (graphicsQueueNodeIndex == UINT32_MAX) { 1888 graphicsQueueNodeIndex = i; 1889 } 1890 1891 if (supportsPresent[i] == VK_TRUE) { 1892 graphicsQueueNodeIndex = i; 1893 presentQueueNodeIndex = i; 1894 break; 1895 } 1896 } 1897 } 1898 if (presentQueueNodeIndex == UINT32_MAX) { 1899 // If didn't find a queue that supports both graphics and present, then 1900 // find a separate present queue. 1901 for (i = 0; i < demo->queue_count; ++i) { 1902 if (supportsPresent[i] == VK_TRUE) { 1903 presentQueueNodeIndex = i; 1904 break; 1905 } 1906 } 1907 } 1908 free(supportsPresent); 1909 1910 // Generate error if could not find both a graphics and a present queue 1911 if (graphicsQueueNodeIndex == UINT32_MAX || 1912 presentQueueNodeIndex == UINT32_MAX) { 1913 ERR_EXIT("Could not find a graphics and a present queue\n", 1914 "Swapchain Initialization Failure"); 1915 } 1916 1917 // TODO: Add support for separate queues, including presentation, 1918 // synchronization, and appropriate tracking for QueueSubmit. 1919 // NOTE: While it is possible for an application to use a separate graphics 1920 // and a present queues, this demo program assumes it is only using 1921 // one: 1922 if (graphicsQueueNodeIndex != presentQueueNodeIndex) { 1923 ERR_EXIT("Could not find a common graphics and a present queue\n", 1924 "Swapchain Initialization Failure"); 1925 } 1926 1927 demo->graphics_queue_node_index = graphicsQueueNodeIndex; 1928 1929 demo_init_device(demo); 1930 1931 vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 0, 1932 &demo->queue); 1933 1934 // Get the list of VkFormat's that are supported: 1935 uint32_t formatCount; 1936 err = vkGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface, 1937 &formatCount, NULL); 1938 assert(!err); 1939 VkSurfaceFormatKHR *surfFormats = 1940 (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); 1941 err = vkGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface, 1942 &formatCount, surfFormats); 1943 assert(!err); 1944 // If the format list includes just one entry of VK_FORMAT_UNDEFINED, 1945 // the surface has no preferred format. Otherwise, at least one 1946 // supported format will be returned. 1947 if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) { 1948 demo->format = VK_FORMAT_B8G8R8A8_UNORM; 1949 } else { 1950 assert(formatCount >= 1); 1951 demo->format = surfFormats[0].format; 1952 } 1953 demo->color_space = surfFormats[0].colorSpace; 1954 1955 demo->curFrame = 0; 1956 1957 // Get Memory information and properties 1958 vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties); 1959} 1960 1961static void demo_init_connection(struct demo *demo) { 1962 glfwSetErrorCallback(demo_error_callback); 1963 1964 if (!glfwInit()) { 1965 printf("Cannot initialize GLFW.\nExiting ...\n"); 1966 fflush(stdout); 1967 exit(1); 1968 } 1969 1970 if (!glfwVulkanSupported()) { 1971 printf("GLFW failed to find the Vulkan loader.\nExiting ...\n"); 1972 fflush(stdout); 1973 exit(1); 1974 } 1975 1976 gladLoadVulkanUserPtr(NULL, (GLADuserptrloadfunc) glfwGetInstanceProcAddress, NULL); 1977} 1978 1979static void demo_init(struct demo *demo, const int argc, const char *argv[]) 1980{ 1981 int i; 1982 memset(demo, 0, sizeof(*demo)); 1983 demo->frameCount = INT32_MAX; 1984 1985 for (i = 1; i < argc; i++) { 1986 if (strcmp(argv[i], "--use_staging") == 0) { 1987 demo->use_staging_buffer = true; 1988 continue; 1989 } 1990 if (strcmp(argv[i], "--break") == 0) { 1991 demo->use_break = true; 1992 continue; 1993 } 1994 if (strcmp(argv[i], "--validate") == 0) { 1995 demo->validate = true; 1996 continue; 1997 } 1998 if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX && 1999 i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 && 2000 demo->frameCount >= 0) { 2001 i++; 2002 continue; 2003 } 2004 2005 fprintf(stderr, "Usage:\n %s [--use_staging] [--validate] [--break] " 2006 "[--c <framecount>]\n", 2007 APP_SHORT_NAME); 2008 fflush(stderr); 2009 exit(1); 2010 } 2011 2012 demo_init_connection(demo); 2013 demo_init_vk(demo); 2014 2015 demo->width = 300; 2016 demo->height = 300; 2017 demo->depthStencil = 1.0; 2018 demo->depthIncrement = -0.01f; 2019} 2020 2021static void demo_cleanup(struct demo *demo) { 2022 uint32_t i; 2023 2024 for (i = 0; i < demo->swapchainImageCount; i++) { 2025 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL); 2026 } 2027 free(demo->framebuffers); 2028 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL); 2029 2030 if (demo->setup_cmd) { 2031 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd); 2032 } 2033 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd); 2034 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL); 2035 2036 vkDestroyPipeline(demo->device, demo->pipeline, NULL); 2037 vkDestroyRenderPass(demo->device, demo->render_pass, NULL); 2038 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL); 2039 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL); 2040 2041 vkDestroyBuffer(demo->device, demo->vertices.buf, NULL); 2042 vkFreeMemory(demo->device, demo->vertices.mem, NULL); 2043 2044 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 2045 vkDestroyImageView(demo->device, demo->textures[i].view, NULL); 2046 vkDestroyImage(demo->device, demo->textures[i].image, NULL); 2047 vkFreeMemory(demo->device, demo->textures[i].mem, NULL); 2048 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL); 2049 } 2050 2051 for (i = 0; i < demo->swapchainImageCount; i++) { 2052 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL); 2053 } 2054 2055 vkDestroyImageView(demo->device, demo->depth.view, NULL); 2056 vkDestroyImage(demo->device, demo->depth.image, NULL); 2057 vkFreeMemory(demo->device, demo->depth.mem, NULL); 2058 2059 vkDestroySwapchainKHR(demo->device, demo->swapchain, NULL); 2060 free(demo->buffers); 2061 2062 vkDestroyDevice(demo->device, NULL); 2063 if (demo->validate) { 2064 vkDestroyDebugReportCallbackEXT(demo->inst, demo->msg_callback, NULL); 2065 } 2066 vkDestroySurfaceKHR(demo->inst, demo->surface, NULL); 2067 vkDestroyInstance(demo->inst, NULL); 2068 2069 free(demo->queue_props); 2070 2071 glfwDestroyWindow(demo->window); 2072 glfwTerminate(); 2073} 2074 2075static void demo_resize(struct demo *demo) { 2076 uint32_t i; 2077 2078 // In order to properly resize the window, we must re-create the swapchain 2079 // AND redo the command buffers, etc. 2080 // 2081 // First, perform part of the demo_cleanup() function: 2082 2083 for (i = 0; i < demo->swapchainImageCount; i++) { 2084 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL); 2085 } 2086 free(demo->framebuffers); 2087 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL); 2088 2089 if (demo->setup_cmd) { 2090 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd); 2091 demo->setup_cmd = VK_NULL_HANDLE; 2092 } 2093 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd); 2094 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL); 2095 2096 vkDestroyPipeline(demo->device, demo->pipeline, NULL); 2097 vkDestroyRenderPass(demo->device, demo->render_pass, NULL); 2098 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL); 2099 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL); 2100 2101 vkDestroyBuffer(demo->device, demo->vertices.buf, NULL); 2102 vkFreeMemory(demo->device, demo->vertices.mem, NULL); 2103 2104 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 2105 vkDestroyImageView(demo->device, demo->textures[i].view, NULL); 2106 vkDestroyImage(demo->device, demo->textures[i].image, NULL); 2107 vkFreeMemory(demo->device, demo->textures[i].mem, NULL); 2108 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL); 2109 } 2110 2111 for (i = 0; i < demo->swapchainImageCount; i++) { 2112 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL); 2113 } 2114 2115 vkDestroyImageView(demo->device, demo->depth.view, NULL); 2116 vkDestroyImage(demo->device, demo->depth.image, NULL); 2117 vkFreeMemory(demo->device, demo->depth.mem, NULL); 2118 2119 free(demo->buffers); 2120 2121 // Second, re-perform the demo_prepare() function, which will re-create the 2122 // swapchain: 2123 demo_prepare(demo); 2124} 2125 2126int main(const int argc, const char *argv[]) { 2127 struct demo demo; 2128 2129 demo_init(&demo, argc, argv); 2130 demo_create_window(&demo); 2131 demo_init_vk_swapchain(&demo); 2132 2133 demo_prepare(&demo); 2134 demo_run(&demo); 2135 2136 demo_cleanup(&demo); 2137 2138 return validation_error; 2139} 2140 2141
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.