cube.c revision 95b8bb3810e626be6e997a4a40e5f6cfc24ca7b0
1/* 2 * Vulkan 3 * 4 * Copyright (C) 2014-2015 LunarG, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24#define _GNU_SOURCE 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28#include <stdbool.h> 29#include <assert.h> 30 31#ifdef _WIN32 32#pragma comment(linker, "/subsystem:windows") 33#include <windows.h> 34#define APP_NAME_STR_LEN 80 35#else // _WIN32 36#include <xcb/xcb.h> 37#endif // _WIN32 38 39#include <vulkan.h> 40#include <vk_ext_khr_swapchain.h> 41#include <vk_ext_khr_device_swapchain.h> 42#include "vk_debug_report_lunarg.h" 43 44#include "icd-spv.h" 45 46#include "vk_sdk_platform.h" 47#include "linmath.h" 48#include <png.h> 49 50#define DEMO_BUFFER_COUNT 2 51#define DEMO_TEXTURE_COUNT 1 52#define APP_SHORT_NAME "cube" 53#define APP_LONG_NAME "The Vulkan Cube Demo Program" 54 55#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 56 57#if defined(NDEBUG) && defined(__GNUC__) 58#define U_ASSERT_ONLY __attribute__((unused)) 59#else 60#define U_ASSERT_ONLY 61#endif 62 63#ifdef _WIN32 64#define ERR_EXIT(err_msg, err_class) \ 65 do { \ 66 MessageBox(NULL, err_msg, err_class, MB_OK); \ 67 exit(1); \ 68 } while (0) 69 70#else // _WIN32 71 72#define ERR_EXIT(err_msg, err_class) \ 73 do { \ 74 printf(err_msg); \ 75 fflush(stdout); \ 76 exit(1); \ 77 } while (0) 78#endif // _WIN32 79 80#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \ 81{ \ 82 demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetInstanceProcAddr(inst, "vk"#entrypoint); \ 83 if (demo->fp##entrypoint == NULL) { \ 84 ERR_EXIT("vkGetInstanceProcAddr failed to find vk"#entrypoint, \ 85 "vkGetInstanceProcAddr Failure"); \ 86 } \ 87} 88 89#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \ 90{ \ 91 demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetDeviceProcAddr(dev, "vk"#entrypoint); \ 92 if (demo->fp##entrypoint == NULL) { \ 93 ERR_EXIT("vkGetDeviceProcAddr failed to find vk"#entrypoint, \ 94 "vkGetDeviceProcAddr Failure"); \ 95 } \ 96} 97 98/* 99 * structure to track all objects related to a texture. 100 */ 101struct texture_object { 102 VkSampler sampler; 103 104 VkImage image; 105 VkImageLayout imageLayout; 106 107 VkDeviceMemory mem; 108 VkImageView view; 109 int32_t tex_width, tex_height; 110}; 111 112static char *tex_files[] = { 113 "lunarg-logo-256x256-solid.png" 114}; 115 116struct vkcube_vs_uniform { 117 // Must start with MVP 118 float mvp[4][4]; 119 float position[12*3][4]; 120 float color[12*3][4]; 121}; 122 123struct vktexcube_vs_uniform { 124 // Must start with MVP 125 float mvp[4][4]; 126 float position[12*3][4]; 127 float attr[12*3][4]; 128}; 129 130//-------------------------------------------------------------------------------------- 131// Mesh and VertexFormat Data 132//-------------------------------------------------------------------------------------- 133struct Vertex 134{ 135 float posX, posY, posZ, posW; // Position data 136 float r, g, b, a; // Color 137}; 138 139struct VertexPosTex 140{ 141 float posX, posY, posZ, posW; // Position data 142 float u, v, s, t; // Texcoord 143}; 144 145#define XYZ1(_x_, _y_, _z_) (_x_), (_y_), (_z_), 1.f 146#define UV(_u_, _v_) (_u_), (_v_), 0.f, 1.f 147 148static const float g_vertex_buffer_data[] = { 149 -1.0f,-1.0f,-1.0f, // -X side 150 -1.0f,-1.0f, 1.0f, 151 -1.0f, 1.0f, 1.0f, 152 -1.0f, 1.0f, 1.0f, 153 -1.0f, 1.0f,-1.0f, 154 -1.0f,-1.0f,-1.0f, 155 156 -1.0f,-1.0f,-1.0f, // -Z side 157 1.0f, 1.0f,-1.0f, 158 1.0f,-1.0f,-1.0f, 159 -1.0f,-1.0f,-1.0f, 160 -1.0f, 1.0f,-1.0f, 161 1.0f, 1.0f,-1.0f, 162 163 -1.0f,-1.0f,-1.0f, // -Y side 164 1.0f,-1.0f,-1.0f, 165 1.0f,-1.0f, 1.0f, 166 -1.0f,-1.0f,-1.0f, 167 1.0f,-1.0f, 1.0f, 168 -1.0f,-1.0f, 1.0f, 169 170 -1.0f, 1.0f,-1.0f, // +Y side 171 -1.0f, 1.0f, 1.0f, 172 1.0f, 1.0f, 1.0f, 173 -1.0f, 1.0f,-1.0f, 174 1.0f, 1.0f, 1.0f, 175 1.0f, 1.0f,-1.0f, 176 177 1.0f, 1.0f,-1.0f, // +X side 178 1.0f, 1.0f, 1.0f, 179 1.0f,-1.0f, 1.0f, 180 1.0f,-1.0f, 1.0f, 181 1.0f,-1.0f,-1.0f, 182 1.0f, 1.0f,-1.0f, 183 184 -1.0f, 1.0f, 1.0f, // +Z side 185 -1.0f,-1.0f, 1.0f, 186 1.0f, 1.0f, 1.0f, 187 -1.0f,-1.0f, 1.0f, 188 1.0f,-1.0f, 1.0f, 189 1.0f, 1.0f, 1.0f, 190}; 191 192static const float g_uv_buffer_data[] = { 193 0.0f, 0.0f, // -X side 194 1.0f, 0.0f, 195 1.0f, 1.0f, 196 1.0f, 1.0f, 197 0.0f, 1.0f, 198 0.0f, 0.0f, 199 200 1.0f, 0.0f, // -Z side 201 0.0f, 1.0f, 202 0.0f, 0.0f, 203 1.0f, 0.0f, 204 1.0f, 1.0f, 205 0.0f, 1.0f, 206 207 1.0f, 1.0f, // -Y side 208 1.0f, 0.0f, 209 0.0f, 0.0f, 210 1.0f, 1.0f, 211 0.0f, 0.0f, 212 0.0f, 1.0f, 213 214 1.0f, 1.0f, // +Y side 215 0.0f, 1.0f, 216 0.0f, 0.0f, 217 1.0f, 1.0f, 218 0.0f, 0.0f, 219 1.0f, 0.0f, 220 221 1.0f, 1.0f, // +X side 222 0.0f, 1.0f, 223 0.0f, 0.0f, 224 0.0f, 0.0f, 225 1.0f, 0.0f, 226 1.0f, 1.0f, 227 228 0.0f, 1.0f, // +Z side 229 0.0f, 0.0f, 230 1.0f, 1.0f, 231 0.0f, 0.0f, 232 1.0f, 0.0f, 233 1.0f, 1.0f, 234}; 235 236void dumpMatrix(const char *note, mat4x4 MVP) 237{ 238 int i; 239 240 printf("%s: \n", note); 241 for (i=0; i<4; i++) { 242 printf("%f, %f, %f, %f\n", MVP[i][0], MVP[i][1], MVP[i][2], MVP[i][3]); 243 } 244 printf("\n"); 245 fflush(stdout); 246} 247 248void dumpVec4(const char *note, vec4 vector) 249{ 250 printf("%s: \n", note); 251 printf("%f, %f, %f, %f\n", vector[0], vector[1], vector[2], vector[3]); 252 printf("\n"); 253 fflush(stdout); 254} 255 256VkBool32 dbgFunc( 257 VkFlags msgFlags, 258 VkDbgObjectType objType, 259 uint64_t srcObject, 260 size_t location, 261 int32_t msgCode, 262 const char* pLayerPrefix, 263 const char* pMsg, 264 void* pUserData) 265{ 266 char *message = (char *) malloc(strlen(pMsg)+100); 267 268 assert (message); 269 270 if (msgFlags & VK_DBG_REPORT_ERROR_BIT) { 271 sprintf(message,"ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 272 } else if (msgFlags & VK_DBG_REPORT_WARN_BIT) { 273 // We know that we're submitting queues without fences, ignore this warning 274 if (strstr(pMsg, "vkQueueSubmit parameter, VkFence fence, is null pointer")){ 275 return false; 276 } 277 sprintf(message,"WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 278 } else { 279 return false; 280 } 281 282#ifdef _WIN32 283 MessageBox(NULL, message, "Alert", MB_OK); 284#else 285 printf("%s\n",message); 286 fflush(stdout); 287#endif 288 free(message); 289 290 /* 291 * false indicates that layer should not bail-out of an 292 * API call that had validation failures. This may mean that the 293 * app dies inside the driver due to invalid parameter(s). 294 * That's what would happen without validation layers, so we'll 295 * keep that behavior here. 296 */ 297 return false; 298} 299 300typedef struct _SwapchainBuffers { 301 VkImage image; 302 VkCmdBuffer cmd; 303 VkImageView view; 304} SwapchainBuffers; 305 306struct demo { 307#ifdef _WIN32 308#define APP_NAME_STR_LEN 80 309 HINSTANCE connection; // hInstance - Windows Instance 310 char name[APP_NAME_STR_LEN]; // Name to put on the window/icon 311 HWND window; // hWnd - window handle 312#else // _WIN32 313 xcb_connection_t *connection; 314 xcb_screen_t *screen; 315 xcb_window_t window; 316 xcb_intern_atom_reply_t *atom_wm_delete_window; 317 VkPlatformHandleXcbKHR platform_handle_xcb; 318#endif // _WIN32 319 bool prepared; 320 bool use_staging_buffer; 321 bool use_glsl; 322 323 VkInstance inst; 324 VkPhysicalDevice gpu; 325 VkDevice device; 326 VkQueue queue; 327 uint32_t graphics_queue_node_index; 328 VkPhysicalDeviceProperties gpu_props; 329 VkQueueFamilyProperties *queue_props; 330 VkPhysicalDeviceMemoryProperties memory_properties; 331 332 VkFramebuffer framebuffer; 333 int width, height; 334 VkFormat format; 335 VkColorSpaceKHR color_space; 336 337 PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR; 338 PFN_vkGetSurfacePropertiesKHR fpGetSurfacePropertiesKHR; 339 PFN_vkGetSurfaceFormatsKHR fpGetSurfaceFormatsKHR; 340 PFN_vkGetSurfacePresentModesKHR fpGetSurfacePresentModesKHR; 341 PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR; 342 PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR; 343 PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR; 344 PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR; 345 PFN_vkQueuePresentKHR fpQueuePresentKHR; 346 VkSurfaceDescriptionWindowKHR surface_description; 347 uint32_t swapchainImageCount; 348 VkSwapchainKHR swap_chain; 349 SwapchainBuffers *buffers; 350 351 VkCmdPool cmd_pool; 352 353 struct { 354 VkFormat format; 355 356 VkImage image; 357 VkDeviceMemory mem; 358 VkImageView view; 359 } depth; 360 361 struct texture_object textures[DEMO_TEXTURE_COUNT]; 362 363 struct { 364 VkBuffer buf; 365 VkDeviceMemory mem; 366 VkDescriptorInfo desc; 367 } uniform_data; 368 369 VkCmdBuffer cmd; // Buffer for initialization commands 370 VkPipelineLayout pipeline_layout; 371 VkDescriptorSetLayout desc_layout; 372 VkPipelineCache pipelineCache; 373 VkRenderPass render_pass; 374 VkPipeline pipeline; 375 376 VkDynamicViewportState dynamic_viewport; 377 VkDynamicLineWidthState dynamic_line_width; 378 VkDynamicDepthBiasState dynamic_depth_bias; 379 VkDynamicBlendState dynamic_blend; 380 VkDynamicDepthBoundsState dynamic_depth_bounds; 381 VkDynamicStencilState dynamic_stencil; 382 383 mat4x4 projection_matrix; 384 mat4x4 view_matrix; 385 mat4x4 model_matrix; 386 387 float spin_angle; 388 float spin_increment; 389 bool pause; 390 391 VkShaderModule vert_shader_module; 392 VkShaderModule frag_shader_module; 393 394 VkDescriptorPool desc_pool; 395 VkDescriptorSet desc_set; 396 397 VkFramebuffer framebuffers[DEMO_BUFFER_COUNT]; 398 399 bool quit; 400 int32_t curFrame; 401 int32_t frameCount; 402 bool validate; 403 bool use_break; 404 PFN_vkDbgCreateMsgCallback dbgCreateMsgCallback; 405 PFN_vkDbgDestroyMsgCallback dbgDestroyMsgCallback; 406 PFN_vkDbgMsgCallback dbgBreakCallback; 407 VkDbgMsgCallback msg_callback; 408 409 uint32_t current_buffer; 410 uint32_t queue_count; 411}; 412 413static VkResult memory_type_from_properties(struct demo *demo, uint32_t typeBits, VkFlags properties, uint32_t *typeIndex) 414{ 415 // Search memtypes to find first index with those properties 416 for (uint32_t i = 0; i < 32; i++) { 417 if ((typeBits & 1) == 1) { 418 // Type is available, does it match user properties? 419 if ((demo->memory_properties.memoryTypes[i].propertyFlags & properties) == properties) { 420 *typeIndex = i; 421 return VK_SUCCESS; 422 } 423 } 424 typeBits >>= 1; 425 } 426 // No memory types matched, return failure 427 return VK_UNSUPPORTED; 428} 429 430static void demo_flush_init_cmd(struct demo *demo) 431{ 432 VkResult U_ASSERT_ONLY err; 433 434 if (demo->cmd == VK_NULL_HANDLE) 435 return; 436 437 err = vkEndCommandBuffer(demo->cmd); 438 assert(!err); 439 440 const VkCmdBuffer cmd_bufs[] = { demo->cmd }; 441 VkFence nullFence = { VK_NULL_HANDLE }; 442 443 err = vkQueueSubmit(demo->queue, 1, cmd_bufs, nullFence); 444 assert(!err); 445 446 err = vkQueueWaitIdle(demo->queue); 447 assert(!err); 448 449 vkDestroyCommandBuffer(demo->device, demo->cmd); 450 demo->cmd = VK_NULL_HANDLE; 451} 452 453static void demo_set_image_layout( 454 struct demo *demo, 455 VkImage image, 456 VkImageAspectFlags aspectMask, 457 VkImageLayout old_image_layout, 458 VkImageLayout new_image_layout) 459{ 460 VkResult U_ASSERT_ONLY err; 461 462 if (demo->cmd == VK_NULL_HANDLE) { 463 const VkCmdBufferCreateInfo cmd = { 464 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO, 465 .pNext = NULL, 466 .cmdPool = demo->cmd_pool, 467 .level = VK_CMD_BUFFER_LEVEL_PRIMARY, 468 .flags = 0, 469 }; 470 471 err = vkCreateCommandBuffer(demo->device, &cmd, &demo->cmd); 472 assert(!err); 473 474 VkCmdBufferBeginInfo cmd_buf_info = { 475 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, 476 .pNext = NULL, 477 .flags = VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | 478 VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT, 479 .renderPass = { VK_NULL_HANDLE }, 480 .subpass = 0, 481 .framebuffer = { VK_NULL_HANDLE }, 482 }; 483 err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info); 484 } 485 486 VkImageMemoryBarrier image_memory_barrier = { 487 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 488 .pNext = NULL, 489 .outputMask = 0, 490 .inputMask = 0, 491 .oldLayout = old_image_layout, 492 .newLayout = new_image_layout, 493 .image = image, 494 .subresourceRange = { aspectMask, 0, 1, 0, 0 } 495 }; 496 497 if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL) { 498 /* Make sure anything that was copying from this image has completed */ 499 image_memory_barrier.inputMask = VK_MEMORY_INPUT_TRANSFER_BIT; 500 } 501 502 if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 503 /* Make sure any Copy or CPU writes to image are flushed */ 504 image_memory_barrier.outputMask = VK_MEMORY_OUTPUT_HOST_WRITE_BIT | VK_MEMORY_OUTPUT_TRANSFER_BIT; 505 } 506 507 VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier; 508 509 VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 510 VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 511 512 vkCmdPipelineBarrier(demo->cmd, src_stages, dest_stages, false, 1, (const void * const*)&pmemory_barrier); 513} 514 515static void demo_draw_build_cmd(struct demo *demo, VkCmdBuffer cmd_buf) 516{ 517 const VkCmdBufferBeginInfo cmd_buf_info = { 518 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, 519 .pNext = NULL, 520 .flags = VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT, 521 .renderPass = { VK_NULL_HANDLE }, 522 .subpass = 0, 523 .framebuffer = { VK_NULL_HANDLE }, 524 }; 525 const VkClearValue clear_values[2] = { 526 [0] = { .color.float32 = { 0.2f, 0.2f, 0.2f, 0.2f } }, 527 [1] = { .depthStencil = { 1.0f, 0 } }, 528 }; 529 const VkRenderPassBeginInfo rp_begin = { 530 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 531 .pNext = NULL, 532 .renderPass = demo->render_pass, 533 .framebuffer = demo->framebuffers[demo->current_buffer], 534 .renderArea.offset.x = 0, 535 .renderArea.offset.y = 0, 536 .renderArea.extent.width = demo->width, 537 .renderArea.extent.height = demo->height, 538 .clearValueCount = 2, 539 .pClearValues = clear_values, 540 }; 541 VkResult U_ASSERT_ONLY err; 542 543 err = vkBeginCommandBuffer(cmd_buf, &cmd_buf_info); 544 assert(!err); 545 546 vkCmdBeginRenderPass(cmd_buf, &rp_begin, VK_RENDER_PASS_CONTENTS_INLINE); 547 548 vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, 549 demo->pipeline); 550 vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline_layout, 551 0, 1, &demo->desc_set, 0, NULL); 552 553 vkCmdBindDynamicViewportState(cmd_buf, demo->dynamic_viewport); 554 vkCmdBindDynamicLineWidthState(cmd_buf, demo->dynamic_line_width); 555 vkCmdBindDynamicDepthBiasState(cmd_buf, demo->dynamic_depth_bias); 556 vkCmdBindDynamicBlendState(cmd_buf, demo->dynamic_blend); 557 vkCmdBindDynamicDepthBoundsState(cmd_buf, demo->dynamic_depth_bounds); 558 vkCmdBindDynamicStencilState(cmd_buf, demo->dynamic_stencil); 559 560 vkCmdDraw(cmd_buf, 0, 12 * 3, 0, 1); 561 vkCmdEndRenderPass(cmd_buf); 562 563 err = vkEndCommandBuffer(cmd_buf); 564 assert(!err); 565} 566 567 568void demo_update_data_buffer(struct demo *demo) 569{ 570 mat4x4 MVP, Model, VP; 571 int matrixSize = sizeof(MVP); 572 uint8_t *pData; 573 VkResult U_ASSERT_ONLY err; 574 575 mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix); 576 577 // Rotate 22.5 degrees around the Y axis 578 mat4x4_dup(Model, demo->model_matrix); 579 mat4x4_rotate(demo->model_matrix, Model, 0.0f, 1.0f, 0.0f, (float)degreesToRadians(demo->spin_angle)); 580 mat4x4_mul(MVP, VP, demo->model_matrix); 581 582 err = vkMapMemory(demo->device, demo->uniform_data.mem, 0, 0, 0, (void **) &pData); 583 assert(!err); 584 585 memcpy(pData, (const void*) &MVP[0][0], matrixSize); 586 587 vkUnmapMemory(demo->device, demo->uniform_data.mem); 588} 589 590static void demo_draw(struct demo *demo) 591{ 592 VkResult U_ASSERT_ONLY err; 593 VkSemaphore presentCompleteSemaphore; 594 VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = { 595 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 596 .pNext = NULL, 597 .flags = VK_FENCE_CREATE_SIGNALED_BIT, 598 }; 599 VkFence nullFence = { VK_NULL_HANDLE }; 600 601 err = vkCreateSemaphore(demo->device, 602 &presentCompleteSemaphoreCreateInfo, 603 &presentCompleteSemaphore); 604 assert(!err); 605 606 // Get the index of the next available swapchain image: 607 err = demo->fpAcquireNextImageKHR(demo->device, demo->swap_chain, 608 UINT64_MAX, 609 presentCompleteSemaphore, 610 &demo->current_buffer); 611 // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR 612 // return codes 613 assert(!err); 614 615 // Wait for the present complete semaphore to be signaled to ensure 616 // that the image won't be rendered to until the presentation 617 // engine has fully released ownership to the application, and it is 618 // okay to render to the image. 619 vkQueueWaitSemaphore(demo->queue, presentCompleteSemaphore); 620 621// FIXME/TODO: DEAL WITH VK_IMAGE_LAYOUT_PRESENT_SOURCE_KHR 622 err = vkQueueSubmit(demo->queue, 1, &demo->buffers[demo->current_buffer].cmd, 623 nullFence); 624 assert(!err); 625 626 VkPresentInfoKHR present = { 627 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 628 .pNext = NULL, 629 .swapchainCount = 1, 630 .swapchains = &demo->swap_chain, 631 .imageIndices = &demo->current_buffer, 632 }; 633 634// TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER? 635 err = demo->fpQueuePresentKHR(demo->queue, &present); 636 // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR 637 // return codes 638 assert(!err); 639 640 err = vkQueueWaitIdle(demo->queue); 641 assert(err == VK_SUCCESS); 642 643 vkDestroySemaphore(demo->device, presentCompleteSemaphore); 644} 645 646static void demo_prepare_buffers(struct demo *demo) 647{ 648 VkResult U_ASSERT_ONLY err; 649 650 // Check the surface properties and formats 651 VkSurfacePropertiesKHR surfProperties; 652 err = demo->fpGetSurfacePropertiesKHR(demo->device, 653 (const VkSurfaceDescriptionKHR *)&demo->surface_description, 654 &surfProperties); 655 assert(!err); 656 657 uint32_t presentModeCount; 658 err = demo->fpGetSurfacePresentModesKHR(demo->device, 659 (const VkSurfaceDescriptionKHR *)&demo->surface_description, 660 &presentModeCount, NULL); 661 assert(!err); 662 VkPresentModeKHR *presentModes = 663 (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR)); 664 assert(presentModes); 665 err = demo->fpGetSurfacePresentModesKHR(demo->device, 666 (const VkSurfaceDescriptionKHR *)&demo->surface_description, 667 &presentModeCount, presentModes); 668 assert(!err); 669 670 VkExtent2D swapchainExtent; 671 // width and height are either both -1, or both not -1. 672 if (surfProperties.currentExtent.width == -1) 673 { 674 // If the surface size is undefined, the size is set to 675 // the size of the images requested. 676 swapchainExtent.width = demo->width; 677 swapchainExtent.height = demo->height; 678 } 679 else 680 { 681 // If the surface size is defined, the swap chain size must match 682 swapchainExtent = surfProperties.currentExtent; 683 } 684 685 // If mailbox mode is available, use it, as is the lowest-latency non- 686 // tearing mode. If not, try IMMEDIATE which will usually be available, 687 // and is fastest (though it tears). If not, fall back to FIFO which is 688 // always available. 689 VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; 690 for (size_t i = 0; i < presentModeCount; i++) { 691 if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { 692 swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; 693 break; 694 } 695 if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && 696 (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) { 697 swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; 698 } 699 } 700 701#define WORK_AROUND_CODE 702#ifdef WORK_AROUND_CODE 703 // After the proper code was created, other parts of this demo were 704 // modified to only support DEMO_BUFFER_COUNT number of command buffers, 705 // images, etc. Live with that for now. 706 // TODO: Rework this demo code to live with the number of buffers returned 707 // by vkCreateSwapchainKHR(). 708 uint32_t desiredNumberOfSwapchainImages = DEMO_BUFFER_COUNT; 709#else // WORK_AROUND_CODE 710 // Determine the number of VkImage's to use in the swap chain (we desire to 711 // own only 1 image at a time, besides the images being displayed and 712 // queued for display): 713 uint32_t desiredNumberOfSwapchainImages = surfProperties.minImageCount + 1; 714 if ((surfProperties.maxImageCount > 0) && 715 (desiredNumberOfSwapchainImages > surfProperties.maxImageCount)) 716 { 717 // Application must settle for fewer images than desired: 718 desiredNumberOfSwapchainImages = surfProperties.maxImageCount; 719 } 720#endif // WORK_AROUND_CODE 721 722 VkSurfaceTransformFlagBitsKHR preTransform; 723 if (surfProperties.supportedTransforms & VK_SURFACE_TRANSFORM_NONE_BIT_KHR) { 724 preTransform = VK_SURFACE_TRANSFORM_NONE_KHR; 725 } else { 726 preTransform = surfProperties.currentTransform; 727 } 728 729 const VkSwapchainCreateInfoKHR swap_chain = { 730 .sType = VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_KHR, 731 .pNext = NULL, 732 .pSurfaceDescription = (const VkSurfaceDescriptionKHR *)&demo->surface_description, 733 .minImageCount = desiredNumberOfSwapchainImages, 734 .imageFormat = demo->format, 735 .imageColorSpace = demo->color_space, 736 .imageExtent = { 737 .width = swapchainExtent.width, 738 .height = swapchainExtent.height, 739 }, 740 .imageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 741 .preTransform = preTransform, 742 .imageArraySize = 1, 743 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 744 .queueFamilyCount = 0, 745 .pQueueFamilyIndices = NULL, 746 .presentMode = swapchainPresentMode, 747 .oldSwapchain.handle = 0, 748 .clipped = true, 749 }; 750 uint32_t i; 751 752 err = demo->fpCreateSwapchainKHR(demo->device, &swap_chain, &demo->swap_chain); 753 assert(!err); 754 755 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swap_chain, 756 &demo->swapchainImageCount, NULL); 757 assert(!err); 758 759 VkImage* swapchainImages = 760 (VkImage*)malloc(demo->swapchainImageCount * sizeof(VkImage)); 761 assert(swapchainImages); 762 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swap_chain, 763 &demo->swapchainImageCount, 764 swapchainImages); 765 assert(!err); 766#ifdef WORK_AROUND_CODE 767 // After the proper code was created, other parts of this demo were 768 // modified to only support DEMO_BUFFER_COUNT number of command buffers, 769 // images, etc. Live with that for now. 770 // TODO: Rework this demo code to live with the number of buffers returned 771 // by vkCreateSwapchainKHR(). 772 demo->swapchainImageCount = DEMO_BUFFER_COUNT; 773#endif // WORK_AROUND_CODE 774 775 demo->buffers = (SwapchainBuffers*)malloc(sizeof(SwapchainBuffers)*demo->swapchainImageCount); 776 assert(demo->buffers); 777 778 for (i = 0; i < demo->swapchainImageCount; i++) { 779 VkImageViewCreateInfo color_image_view = { 780 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 781 .pNext = NULL, 782 .format = demo->format, 783 .channels = { 784 .r = VK_CHANNEL_SWIZZLE_R, 785 .g = VK_CHANNEL_SWIZZLE_G, 786 .b = VK_CHANNEL_SWIZZLE_B, 787 .a = VK_CHANNEL_SWIZZLE_A, 788 }, 789 .subresourceRange = { 790 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 791 .baseMipLevel = 0, 792 .mipLevels = 1, 793 .baseArrayLayer = 0, 794 .arraySize = 1 795 }, 796 .viewType = VK_IMAGE_VIEW_TYPE_2D, 797 .flags = 0, 798 }; 799 800 demo->buffers[i].image = swapchainImages[i]; 801 802 demo_set_image_layout(demo, demo->buffers[i].image, 803 VK_IMAGE_ASPECT_COLOR, 804 VK_IMAGE_LAYOUT_UNDEFINED, 805 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 806 807 color_image_view.image = demo->buffers[i].image; 808 809 err = vkCreateImageView(demo->device, 810 &color_image_view, &demo->buffers[i].view); 811 assert(!err); 812 } 813} 814 815static void demo_prepare_depth(struct demo *demo) 816{ 817 const VkFormat depth_format = VK_FORMAT_D16_UNORM; 818 const VkImageCreateInfo image = { 819 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 820 .pNext = NULL, 821 .imageType = VK_IMAGE_TYPE_2D, 822 .format = depth_format, 823 .extent = { demo->width, demo->height, 1 }, 824 .mipLevels = 1, 825 .arraySize = 1, 826 .samples = 1, 827 .tiling = VK_IMAGE_TILING_OPTIMAL, 828 .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 829 .flags = 0, 830 }; 831 VkMemoryAllocInfo mem_alloc = { 832 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 833 .pNext = NULL, 834 .allocationSize = 0, 835 .memoryTypeIndex = 0, 836 }; 837 VkImageViewCreateInfo view = { 838 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 839 .pNext = NULL, 840 .image.handle = VK_NULL_HANDLE, 841 .format = depth_format, 842 .subresourceRange = { 843 .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, 844 .baseMipLevel = 0, 845 .mipLevels = 1, 846 .baseArrayLayer = 0, 847 .arraySize = 1 848 }, 849 .flags = 0, 850 .viewType = VK_IMAGE_VIEW_TYPE_2D, 851 }; 852 853 VkMemoryRequirements mem_reqs; 854 VkResult U_ASSERT_ONLY err; 855 856 demo->depth.format = depth_format; 857 858 /* create image */ 859 err = vkCreateImage(demo->device, &image, 860 &demo->depth.image); 861 assert(!err); 862 863 err = vkGetImageMemoryRequirements(demo->device, 864 demo->depth.image, &mem_reqs); 865 866 mem_alloc.allocationSize = mem_reqs.size; 867 err = memory_type_from_properties(demo, 868 mem_reqs.memoryTypeBits, 869 VK_MEMORY_PROPERTY_DEVICE_ONLY, 870 &mem_alloc.memoryTypeIndex); 871 assert(!err); 872 873 /* allocate memory */ 874 err = vkAllocMemory(demo->device, &mem_alloc, &demo->depth.mem); 875 assert(!err); 876 877 /* bind memory */ 878 err = vkBindImageMemory(demo->device, demo->depth.image, 879 demo->depth.mem, 0); 880 assert(!err); 881 882 demo_set_image_layout(demo, demo->depth.image, 883 VK_IMAGE_ASPECT_DEPTH_BIT, 884 VK_IMAGE_LAYOUT_UNDEFINED, 885 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); 886 887 /* create image view */ 888 view.image = demo->depth.image; 889 err = vkCreateImageView(demo->device, &view, &demo->depth.view); 890 assert(!err); 891} 892 893/** loadTexture 894 * loads a png file into an memory object, using cstdio , libpng. 895 * 896 * \param demo : Needed to access VK calls 897 * \param filename : the png file to be loaded 898 * \param width : width of png, to be updated as a side effect of this function 899 * \param height : height of png, to be updated as a side effect of this function 900 * 901 * \return bool : an opengl texture id. true if successful?, 902 * should be validated by the client of this function. 903 * 904 * Source: http://en.wikibooks.org/wiki/OpenGL_Programming/Intermediate/Textures 905 * Modified to copy image to memory 906 * 907 */ 908bool loadTexture(const char *filename, uint8_t *rgba_data, 909 VkSubresourceLayout *layout, 910 int32_t *width, int32_t *height) 911{ 912 //header for testing if it is a png 913 png_byte header[8]; 914 int is_png, bit_depth, color_type, rowbytes; 915 size_t retval; 916 png_uint_32 i, twidth, theight; 917 png_structp png_ptr; 918 png_infop info_ptr, end_info; 919 png_byte *image_data; 920 png_bytep *row_pointers; 921 922 //open file as binary 923 FILE *fp = fopen(filename, "rb"); 924 if (!fp) { 925 return false; 926 } 927 928 //read the header 929 retval = fread(header, 1, 8, fp); 930 if (retval != 8) { 931 fclose(fp); 932 return false; 933 } 934 935 //test if png 936 is_png = !png_sig_cmp(header, 0, 8); 937 if (!is_png) { 938 fclose(fp); 939 return false; 940 } 941 942 //create png struct 943 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, 944 NULL, NULL); 945 if (!png_ptr) { 946 fclose(fp); 947 return (false); 948 } 949 950 //create png info struct 951 info_ptr = png_create_info_struct(png_ptr); 952 if (!info_ptr) { 953 png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); 954 fclose(fp); 955 return (false); 956 } 957 958 //create png info struct 959 end_info = png_create_info_struct(png_ptr); 960 if (!end_info) { 961 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); 962 fclose(fp); 963 return (false); 964 } 965 966 //png error stuff, not sure libpng man suggests this. 967 if (setjmp(png_jmpbuf(png_ptr))) { 968 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); 969 fclose(fp); 970 return (false); 971 } 972 973 //init png reading 974 png_init_io(png_ptr, fp); 975 976 //let libpng know you already read the first 8 bytes 977 png_set_sig_bytes(png_ptr, 8); 978 979 // read all the info up to the image data 980 png_read_info(png_ptr, info_ptr); 981 982 // get info about png 983 png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type, 984 NULL, NULL, NULL); 985 986 //update width and height based on png info 987 *width = twidth; 988 *height = theight; 989 990 // Require that incoming texture be 8bits per color component 991 // and 4 components (RGBA). 992 if (png_get_bit_depth(png_ptr, info_ptr) != 8 || 993 png_get_channels(png_ptr, info_ptr) != 4) { 994 return false; 995 } 996 997 if (rgba_data == NULL) { 998 // If data pointer is null, we just want the width & height 999 // clean up memory and close stuff 1000 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); 1001 fclose(fp); 1002 1003 return true; 1004 } 1005 1006 // Update the png info struct. 1007 png_read_update_info(png_ptr, info_ptr); 1008 1009 // Row size in bytes. 1010 rowbytes = png_get_rowbytes(png_ptr, info_ptr); 1011 1012 // Allocate the image_data as a big block, to be given to opengl 1013 image_data = (png_byte *)malloc(rowbytes * theight * sizeof(png_byte)); 1014 if (!image_data) { 1015 //clean up memory and close stuff 1016 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); 1017 fclose(fp); 1018 return false; 1019 } 1020 1021 // row_pointers is for pointing to image_data for reading the png with libpng 1022 row_pointers = (png_bytep *)malloc(theight * sizeof(png_bytep)); 1023 if (!row_pointers) { 1024 //clean up memory and close stuff 1025 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); 1026 // delete[] image_data; 1027 fclose(fp); 1028 return false; 1029 } 1030 // set the individual row_pointers to point at the correct offsets of image_data 1031 for (i = 0; i < theight; ++i) 1032 row_pointers[theight - 1 - i] = rgba_data + i * layout->rowPitch; 1033 1034 // read the png into image_data through row_pointers 1035 png_read_image(png_ptr, row_pointers); 1036 1037 // clean up memory and close stuff 1038 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); 1039 free(row_pointers); 1040 free(image_data); 1041 fclose(fp); 1042 1043 return true; 1044} 1045 1046static void demo_prepare_texture_image(struct demo *demo, 1047 const char *filename, 1048 struct texture_object *tex_obj, 1049 VkImageTiling tiling, 1050 VkImageUsageFlags usage, 1051 VkFlags mem_props) 1052{ 1053 const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM; 1054 int32_t tex_width; 1055 int32_t tex_height; 1056 VkResult U_ASSERT_ONLY err; 1057 1058 if (!loadTexture(filename, NULL, NULL, &tex_width, &tex_height)) 1059 { 1060 printf("Failed to load textures\n"); 1061 fflush(stdout); 1062 exit(1); 1063 } 1064 1065 tex_obj->tex_width = tex_width; 1066 tex_obj->tex_height = tex_height; 1067 1068 const VkImageCreateInfo image_create_info = { 1069 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 1070 .pNext = NULL, 1071 .imageType = VK_IMAGE_TYPE_2D, 1072 .format = tex_format, 1073 .extent = { tex_width, tex_height, 1 }, 1074 .mipLevels = 1, 1075 .arraySize = 1, 1076 .samples = 1, 1077 .tiling = tiling, 1078 .usage = usage, 1079 .flags = 0, 1080 }; 1081 VkMemoryAllocInfo mem_alloc = { 1082 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 1083 .pNext = NULL, 1084 .allocationSize = 0, 1085 .memoryTypeIndex = 0, 1086 }; 1087 1088 VkMemoryRequirements mem_reqs; 1089 1090 err = vkCreateImage(demo->device, &image_create_info, 1091 &tex_obj->image); 1092 assert(!err); 1093 1094 err = vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs); 1095 assert(!err); 1096 1097 mem_alloc.allocationSize = mem_reqs.size; 1098 1099 err = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, mem_props, &mem_alloc.memoryTypeIndex); 1100 assert(!err); 1101 1102 /* allocate memory */ 1103 err = vkAllocMemory(demo->device, &mem_alloc, 1104 &(tex_obj->mem)); 1105 assert(!err); 1106 1107 /* bind memory */ 1108 err = vkBindImageMemory(demo->device, tex_obj->image, 1109 tex_obj->mem, 0); 1110 assert(!err); 1111 1112 if (mem_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { 1113 const VkImageSubresource subres = { 1114 .aspect = VK_IMAGE_ASPECT_COLOR, 1115 .mipLevel = 0, 1116 .arrayLayer = 0, 1117 }; 1118 VkSubresourceLayout layout; 1119 void *data; 1120 1121 err = vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres, &layout); 1122 assert(!err); 1123 1124 err = vkMapMemory(demo->device, tex_obj->mem, 0, 0, 0, &data); 1125 assert(!err); 1126 1127 if (!loadTexture(filename, data, &layout, &tex_width, &tex_height)) { 1128 fprintf(stderr, "Error loading texture: %s\n", filename); 1129 } 1130 1131 vkUnmapMemory(demo->device, tex_obj->mem); 1132 } 1133 1134 tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 1135 demo_set_image_layout(demo, tex_obj->image, 1136 VK_IMAGE_ASPECT_COLOR, 1137 VK_IMAGE_LAYOUT_UNDEFINED, 1138 tex_obj->imageLayout); 1139 /* setting the image layout does not reference the actual memory so no need to add a mem ref */ 1140} 1141 1142static void demo_destroy_texture_image(struct demo *demo, struct texture_object *tex_objs) 1143{ 1144 /* clean up staging resources */ 1145 vkFreeMemory(demo->device, tex_objs->mem); 1146 vkDestroyImage(demo->device, tex_objs->image); 1147} 1148 1149static void demo_prepare_textures(struct demo *demo) 1150{ 1151 const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM; 1152 VkFormatProperties props; 1153 VkResult U_ASSERT_ONLY err; 1154 uint32_t i; 1155 1156 err = vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props); 1157 assert(!err); 1158 1159 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1160 1161 if ((props.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && !demo->use_staging_buffer) { 1162 /* Device can texture using linear textures */ 1163 demo_prepare_texture_image(demo, tex_files[i], &demo->textures[i], 1164 VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); 1165 } else if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { 1166 /* Must use staging buffer to copy linear texture to optimized */ 1167 struct texture_object staging_texture; 1168 1169 memset(&staging_texture, 0, sizeof(staging_texture)); 1170 demo_prepare_texture_image(demo, tex_files[i], &staging_texture, 1171 VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); 1172 1173 demo_prepare_texture_image(demo, tex_files[i], &demo->textures[i], 1174 VK_IMAGE_TILING_OPTIMAL, 1175 (VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT | VK_IMAGE_USAGE_SAMPLED_BIT), 1176 VK_MEMORY_PROPERTY_DEVICE_ONLY); 1177 1178 demo_set_image_layout(demo, staging_texture.image, 1179 VK_IMAGE_ASPECT_COLOR, 1180 staging_texture.imageLayout, 1181 VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL); 1182 1183 demo_set_image_layout(demo, demo->textures[i].image, 1184 VK_IMAGE_ASPECT_COLOR, 1185 demo->textures[i].imageLayout, 1186 VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL); 1187 1188 VkImageCopy copy_region = { 1189 .srcSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 }, 1190 .srcOffset = { 0, 0, 0 }, 1191 .destSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 }, 1192 .destOffset = { 0, 0, 0 }, 1193 .extent = { staging_texture.tex_width, staging_texture.tex_height, 1 }, 1194 }; 1195 vkCmdCopyImage(demo->cmd, 1196 staging_texture.image, VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, 1197 demo->textures[i].image, VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, 1198 1, ©_region); 1199 1200 demo_set_image_layout(demo, demo->textures[i].image, 1201 VK_IMAGE_ASPECT_COLOR, 1202 VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, 1203 demo->textures[i].imageLayout); 1204 1205 demo_flush_init_cmd(demo); 1206 1207 demo_destroy_texture_image(demo, &staging_texture); 1208 } else { 1209 /* Can't support VK_FORMAT_R8G8B8A8_UNORM !? */ 1210 assert(!"No support for R8G8B8A8_UNORM as texture image format"); 1211 } 1212 1213 const VkSamplerCreateInfo sampler = { 1214 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 1215 .pNext = NULL, 1216 .magFilter = VK_TEX_FILTER_NEAREST, 1217 .minFilter = VK_TEX_FILTER_NEAREST, 1218 .mipMode = VK_TEX_MIPMAP_MODE_BASE, 1219 .addressModeU = VK_TEX_ADDRESS_MODE_CLAMP, 1220 .addressModeV = VK_TEX_ADDRESS_MODE_CLAMP, 1221 .addressModeW = VK_TEX_ADDRESS_MODE_CLAMP, 1222 .mipLodBias = 0.0f, 1223 .maxAnisotropy = 1, 1224 .compareOp = VK_COMPARE_OP_NEVER, 1225 .minLod = 0.0f, 1226 .maxLod = 0.0f, 1227 .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, 1228 .unnormalizedCoordinates = VK_FALSE, 1229 }; 1230 1231 VkImageViewCreateInfo view = { 1232 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 1233 .pNext = NULL, 1234 .image.handle = VK_NULL_HANDLE, 1235 .viewType = VK_IMAGE_VIEW_TYPE_2D, 1236 .format = tex_format, 1237 .channels = { VK_CHANNEL_SWIZZLE_R, 1238 VK_CHANNEL_SWIZZLE_G, 1239 VK_CHANNEL_SWIZZLE_B, 1240 VK_CHANNEL_SWIZZLE_A, }, 1241 .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, 1242 .flags = 0, 1243 }; 1244 1245 /* create sampler */ 1246 err = vkCreateSampler(demo->device, &sampler, 1247 &demo->textures[i].sampler); 1248 assert(!err); 1249 1250 /* create image view */ 1251 view.image = demo->textures[i].image; 1252 err = vkCreateImageView(demo->device, &view, 1253 &demo->textures[i].view); 1254 assert(!err); 1255 } 1256} 1257 1258void demo_prepare_cube_data_buffer(struct demo *demo) 1259{ 1260 VkBufferCreateInfo buf_info; 1261 VkMemoryAllocInfo alloc_info = { 1262 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 1263 .pNext = NULL, 1264 .allocationSize = 0, 1265 .memoryTypeIndex = 0, 1266 }; 1267 VkMemoryRequirements mem_reqs; 1268 uint8_t *pData; 1269 int i; 1270 mat4x4 MVP, VP; 1271 VkResult U_ASSERT_ONLY err; 1272 struct vktexcube_vs_uniform data; 1273 1274 mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix); 1275 mat4x4_mul(MVP, VP, demo->model_matrix); 1276 memcpy(data.mvp, MVP, sizeof(MVP)); 1277// dumpMatrix("MVP", MVP); 1278 1279 for (i=0; i<12*3; i++) { 1280 data.position[i][0] = g_vertex_buffer_data[i*3]; 1281 data.position[i][1] = g_vertex_buffer_data[i*3+1]; 1282 data.position[i][2] = g_vertex_buffer_data[i*3+2]; 1283 data.position[i][3] = 1.0f; 1284 data.attr[i][0] = g_uv_buffer_data[2*i]; 1285 data.attr[i][1] = g_uv_buffer_data[2*i + 1]; 1286 data.attr[i][2] = 0; 1287 data.attr[i][3] = 0; 1288 } 1289 1290 memset(&buf_info, 0, sizeof(buf_info)); 1291 buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 1292 buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; 1293 buf_info.size = sizeof(data); 1294 err = vkCreateBuffer(demo->device, &buf_info, &demo->uniform_data.buf); 1295 assert(!err); 1296 1297 err = vkGetBufferMemoryRequirements(demo->device, demo->uniform_data.buf, &mem_reqs); 1298 assert(!err); 1299 1300 alloc_info.allocationSize = mem_reqs.size; 1301 err = memory_type_from_properties(demo, 1302 mem_reqs.memoryTypeBits, 1303 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 1304 &alloc_info.memoryTypeIndex); 1305 assert(!err); 1306 1307 err = vkAllocMemory(demo->device, &alloc_info, &(demo->uniform_data.mem)); 1308 assert(!err); 1309 1310 err = vkMapMemory(demo->device, demo->uniform_data.mem, 0, 0, 0, (void **) &pData); 1311 assert(!err); 1312 1313 memcpy(pData, &data, sizeof data); 1314 1315 vkUnmapMemory(demo->device, demo->uniform_data.mem); 1316 1317 err = vkBindBufferMemory(demo->device, 1318 demo->uniform_data.buf, 1319 demo->uniform_data.mem, 0); 1320 assert(!err); 1321 1322 demo->uniform_data.desc.bufferInfo.buffer = demo->uniform_data.buf; 1323 demo->uniform_data.desc.bufferInfo.offset = 0; 1324 demo->uniform_data.desc.bufferInfo.range = sizeof(data); 1325} 1326 1327static void demo_prepare_descriptor_layout(struct demo *demo) 1328{ 1329 const VkDescriptorSetLayoutBinding layout_bindings[2] = { 1330 [0] = { 1331 .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1332 .arraySize = 1, 1333 .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, 1334 .pImmutableSamplers = NULL, 1335 }, 1336 [1] = { 1337 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1338 .arraySize = DEMO_TEXTURE_COUNT, 1339 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, 1340 .pImmutableSamplers = NULL, 1341 }, 1342 }; 1343 const VkDescriptorSetLayoutCreateInfo descriptor_layout = { 1344 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 1345 .pNext = NULL, 1346 .count = 2, 1347 .pBinding = layout_bindings, 1348 }; 1349 VkResult U_ASSERT_ONLY err; 1350 1351 err = vkCreateDescriptorSetLayout(demo->device, 1352 &descriptor_layout, &demo->desc_layout); 1353 assert(!err); 1354 1355 const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = { 1356 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 1357 .pNext = NULL, 1358 .descriptorSetCount = 1, 1359 .pSetLayouts = &demo->desc_layout, 1360 }; 1361 1362 err = vkCreatePipelineLayout(demo->device, 1363 &pPipelineLayoutCreateInfo, 1364 &demo->pipeline_layout); 1365 assert(!err); 1366} 1367 1368static void demo_prepare_render_pass(struct demo *demo) 1369{ 1370 const VkAttachmentDescription attachments[2] = { 1371 [0] = { 1372 .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION, 1373 .pNext = NULL, 1374 .format = demo->format, 1375 .samples = 1, 1376 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 1377 .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 1378 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 1379 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1380 .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1381 .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1382 }, 1383 [1] = { 1384 .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION, 1385 .pNext = NULL, 1386 .format = demo->depth.format, 1387 .samples = 1, 1388 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 1389 .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1390 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 1391 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1392 .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1393 .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1394 }, 1395 }; 1396 const VkAttachmentReference color_reference = { 1397 .attachment = 0, 1398 .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1399 }; 1400 const VkSubpassDescription subpass = { 1401 .sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION, 1402 .pNext = NULL, 1403 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, 1404 .flags = 0, 1405 .inputCount = 0, 1406 .pInputAttachments = NULL, 1407 .colorCount = 1, 1408 .pColorAttachments = &color_reference, 1409 .pResolveAttachments = NULL, 1410 .depthStencilAttachment = { 1411 .attachment = 1, 1412 .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1413 }, 1414 .preserveCount = 0, 1415 .pPreserveAttachments = NULL, 1416 }; 1417 const VkRenderPassCreateInfo rp_info = { 1418 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 1419 .pNext = NULL, 1420 .attachmentCount = 2, 1421 .pAttachments = attachments, 1422 .subpassCount = 1, 1423 .pSubpasses = &subpass, 1424 .dependencyCount = 0, 1425 .pDependencies = NULL, 1426 }; 1427 VkResult U_ASSERT_ONLY err; 1428 1429 err = vkCreateRenderPass(demo->device, &rp_info, &demo->render_pass); 1430 assert(!err); 1431} 1432 1433static VkShader demo_prepare_shader(struct demo* demo, 1434 VkShaderStage stage, 1435 VkShaderModule* pShaderModule, 1436 const void* code, 1437 size_t size) 1438{ 1439 VkShaderModuleCreateInfo moduleCreateInfo; 1440 VkShaderCreateInfo shaderCreateInfo; 1441 VkShader shader; 1442 VkResult err; 1443 1444 1445 moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 1446 moduleCreateInfo.pNext = NULL; 1447 1448 shaderCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO; 1449 shaderCreateInfo.pNext = NULL; 1450 shaderCreateInfo.pName = "main"; 1451 1452 if (!demo->use_glsl) { 1453 moduleCreateInfo.codeSize = size; 1454 moduleCreateInfo.pCode = code; 1455 moduleCreateInfo.flags = 0; 1456 err = vkCreateShaderModule(demo->device, &moduleCreateInfo, pShaderModule); 1457 if (err) { 1458 free((void *) moduleCreateInfo.pCode); 1459 } 1460 1461 shaderCreateInfo.flags = 0; 1462 shaderCreateInfo.module = *pShaderModule; 1463 shaderCreateInfo.pName = "main"; 1464 shaderCreateInfo.stage = stage; 1465 err = vkCreateShader(demo->device, &shaderCreateInfo, &shader); 1466 } else { 1467 // Create fake SPV structure to feed GLSL 1468 // to the driver "under the covers" 1469 moduleCreateInfo.codeSize = 3 * sizeof(uint32_t) + size + 1; 1470 moduleCreateInfo.pCode = malloc(moduleCreateInfo.codeSize); 1471 moduleCreateInfo.flags = 0; 1472 1473 /* try version 0 first: VkShaderStage followed by GLSL */ 1474 ((uint32_t *) moduleCreateInfo.pCode)[0] = ICD_SPV_MAGIC; 1475 ((uint32_t *) moduleCreateInfo.pCode)[1] = 0; 1476 ((uint32_t *) moduleCreateInfo.pCode)[2] = stage; 1477 memcpy(((uint32_t *) moduleCreateInfo.pCode + 3), code, size + 1); 1478 1479 err = vkCreateShaderModule(demo->device, &moduleCreateInfo, pShaderModule); 1480 if (err) { 1481 free((void *) moduleCreateInfo.pCode); 1482 } 1483 1484 shaderCreateInfo.flags = 0; 1485 shaderCreateInfo.module = *pShaderModule; 1486 shaderCreateInfo.pName = "main"; 1487 shaderCreateInfo.stage = stage; 1488 err = vkCreateShader(demo->device, &shaderCreateInfo, &shader); 1489 } 1490 return shader; 1491} 1492 1493char *demo_read_spv(const char *filename, size_t *psize) 1494{ 1495 long int size; 1496 size_t U_ASSERT_ONLY retval; 1497 void *shader_code; 1498 1499 FILE *fp = fopen(filename, "rb"); 1500 if (!fp) return NULL; 1501 1502 fseek(fp, 0L, SEEK_END); 1503 size = ftell(fp); 1504 1505 fseek(fp, 0L, SEEK_SET); 1506 1507 shader_code = malloc(size); 1508 retval = fread(shader_code, size, 1, fp); 1509 assert(retval == 1); 1510 1511 *psize = size; 1512 1513 return shader_code; 1514} 1515 1516static VkShader demo_prepare_vs(struct demo *demo) 1517{ 1518 if (!demo->use_glsl) { 1519 void *vertShaderCode; 1520 size_t size; 1521 1522 vertShaderCode = demo_read_spv("cube-vert.spv", &size); 1523 1524 return demo_prepare_shader(demo, VK_SHADER_STAGE_VERTEX, &demo->vert_shader_module, 1525 vertShaderCode, size); 1526 } else { 1527 static const char *vertShaderText = 1528 "#version 140\n" 1529 "#extension GL_ARB_separate_shader_objects : enable\n" 1530 "#extension GL_ARB_shading_language_420pack : enable\n" 1531 "\n" 1532 "layout(binding = 0) uniform buf {\n" 1533 " mat4 MVP;\n" 1534 " vec4 position[12*3];\n" 1535 " vec4 attr[12*3];\n" 1536 "} ubuf;\n" 1537 "\n" 1538 "layout (location = 0) out vec4 texcoord;\n" 1539 "\n" 1540 "void main() \n" 1541 "{\n" 1542 " texcoord = ubuf.attr[gl_VertexID];\n" 1543 " gl_Position = ubuf.MVP * ubuf.position[gl_VertexID];\n" 1544 "\n" 1545 " // GL->VK conventions\n" 1546 " gl_Position.y = -gl_Position.y;\n" 1547 " gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0;\n" 1548 "}\n"; 1549 1550 return demo_prepare_shader(demo, VK_SHADER_STAGE_VERTEX, &demo->vert_shader_module, 1551 (const void *) vertShaderText, 1552 strlen(vertShaderText)); 1553 } 1554} 1555 1556static VkShader demo_prepare_fs(struct demo *demo) 1557{ 1558 if (!demo->use_glsl) { 1559 void *fragShaderCode; 1560 size_t size; 1561 1562 fragShaderCode = demo_read_spv("cube-frag.spv", &size); 1563 1564 return demo_prepare_shader(demo, VK_SHADER_STAGE_FRAGMENT, &demo->frag_shader_module, 1565 fragShaderCode, size); 1566 } else { 1567 static const char *fragShaderText = 1568 "#version 140\n" 1569 "#extension GL_ARB_separate_shader_objects : enable\n" 1570 "#extension GL_ARB_shading_language_420pack : enable\n" 1571 "layout (binding = 1) uniform sampler2D tex;\n" 1572 "\n" 1573 "layout (location = 0) in vec4 texcoord;\n" 1574 "layout (location = 0) out vec4 uFragColor;\n" 1575 "void main() {\n" 1576 " uFragColor = texture(tex, texcoord.xy);\n" 1577 "}\n"; 1578 1579 return demo_prepare_shader(demo, VK_SHADER_STAGE_FRAGMENT, &demo->frag_shader_module, 1580 (const void *) fragShaderText, 1581 strlen(fragShaderText)); 1582 } 1583} 1584 1585static void demo_prepare_pipeline(struct demo *demo) 1586{ 1587 VkGraphicsPipelineCreateInfo pipeline; 1588 VkPipelineCacheCreateInfo pipelineCache; 1589 VkPipelineInputAssemblyStateCreateInfo ia; 1590 VkPipelineRasterStateCreateInfo rs; 1591 VkPipelineColorBlendStateCreateInfo cb; 1592 VkPipelineDepthStencilStateCreateInfo ds; 1593 VkPipelineViewportStateCreateInfo vp; 1594 VkPipelineMultisampleStateCreateInfo ms; 1595 VkResult U_ASSERT_ONLY err; 1596 1597 memset(&pipeline, 0, sizeof(pipeline)); 1598 pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 1599 pipeline.layout = demo->pipeline_layout; 1600 1601 memset(&ia, 0, sizeof(ia)); 1602 ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 1603 ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 1604 1605 memset(&rs, 0, sizeof(rs)); 1606 rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO; 1607 rs.fillMode = VK_FILL_MODE_SOLID; 1608 rs.cullMode = VK_CULL_MODE_BACK; 1609 rs.frontFace = VK_FRONT_FACE_CCW; 1610 rs.depthClipEnable = VK_TRUE; 1611 rs.rasterizerDiscardEnable = VK_FALSE; 1612 rs.depthBiasEnable = VK_FALSE; 1613 1614 memset(&cb, 0, sizeof(cb)); 1615 cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 1616 VkPipelineColorBlendAttachmentState att_state[1]; 1617 memset(att_state, 0, sizeof(att_state)); 1618 att_state[0].channelWriteMask = 0xf; 1619 att_state[0].blendEnable = VK_FALSE; 1620 cb.attachmentCount = 1; 1621 cb.pAttachments = att_state; 1622 1623 memset(&vp, 0, sizeof(vp)); 1624 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 1625 vp.viewportCount = 1; 1626 1627 memset(&ds, 0, sizeof(ds)); 1628 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; 1629 ds.depthTestEnable = VK_TRUE; 1630 ds.depthWriteEnable = VK_TRUE; 1631 ds.depthCompareOp = VK_COMPARE_OP_LESS_EQUAL; 1632 ds.depthBoundsTestEnable = VK_FALSE; 1633 ds.back.stencilFailOp = VK_STENCIL_OP_KEEP; 1634 ds.back.stencilPassOp = VK_STENCIL_OP_KEEP; 1635 ds.back.stencilCompareOp = VK_COMPARE_OP_ALWAYS; 1636 ds.stencilTestEnable = VK_FALSE; 1637 ds.front = ds.back; 1638 1639 memset(&ms, 0, sizeof(ms)); 1640 ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 1641 ms.pSampleMask = NULL; 1642 ms.rasterSamples = 1; 1643 1644 // Two stages: vs and fs 1645 pipeline.stageCount = 2; 1646 VkPipelineShaderStageCreateInfo shaderStages[2]; 1647 memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo)); 1648 1649 shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1650 shaderStages[0].stage = VK_SHADER_STAGE_VERTEX; 1651 shaderStages[0].shader = demo_prepare_vs(demo); 1652 1653 shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1654 shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT; 1655 shaderStages[1].shader = demo_prepare_fs(demo); 1656 1657 memset(&pipelineCache, 0, sizeof(pipelineCache)); 1658 pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; 1659 1660 err = vkCreatePipelineCache(demo->device, &pipelineCache, &demo->pipelineCache); 1661 assert(!err); 1662 1663 pipeline.pVertexInputState = NULL; 1664 pipeline.pInputAssemblyState = &ia; 1665 pipeline.pRasterState = &rs; 1666 pipeline.pColorBlendState = &cb; 1667 pipeline.pMultisampleState = &ms; 1668 pipeline.pViewportState = &vp; 1669 pipeline.pDepthStencilState = &ds; 1670 pipeline.pStages = shaderStages; 1671 pipeline.renderPass = demo->render_pass; 1672 1673 pipeline.renderPass = demo->render_pass; 1674 1675 err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1, &pipeline, &demo->pipeline); 1676 assert(!err); 1677 1678 for (uint32_t i = 0; i < pipeline.stageCount; i++) { 1679 vkDestroyShader(demo->device, shaderStages[i].shader); 1680 } 1681 vkDestroyShaderModule(demo->device, demo->frag_shader_module); 1682 vkDestroyShaderModule(demo->device, demo->vert_shader_module); 1683} 1684 1685static void demo_prepare_dynamic_states(struct demo *demo) 1686{ 1687 VkDynamicViewportStateCreateInfo viewport_create; 1688 VkDynamicLineWidthStateCreateInfo line_width; 1689 VkDynamicDepthBiasStateCreateInfo depth_bias; 1690 VkDynamicBlendStateCreateInfo blend; 1691 VkDynamicDepthBoundsStateCreateInfo depth_bounds; 1692 VkDynamicStencilStateCreateInfo stencil; 1693 VkResult U_ASSERT_ONLY err; 1694 1695 memset(&viewport_create, 0, sizeof(viewport_create)); 1696 viewport_create.sType = VK_STRUCTURE_TYPE_DYNAMIC_VIEWPORT_STATE_CREATE_INFO; 1697 viewport_create.viewportAndScissorCount = 1; 1698 VkViewport viewport; 1699 memset(&viewport, 0, sizeof(viewport)); 1700 viewport.height = (float) demo->height; 1701 viewport.width = (float) demo->width; 1702 viewport.minDepth = (float) 0.0f; 1703 viewport.maxDepth = (float) 1.0f; 1704 viewport_create.pViewports = &viewport; 1705 VkRect2D scissor; 1706 memset(&scissor, 0, sizeof(scissor)); 1707 scissor.extent.width = demo->width; 1708 scissor.extent.height = demo->height; 1709 scissor.offset.x = 0; 1710 scissor.offset.y = 0; 1711 viewport_create.pScissors = &scissor; 1712 1713 memset(&line_width, 0, sizeof(line_width)); 1714 line_width.sType = VK_STRUCTURE_TYPE_DYNAMIC_LINE_WIDTH_STATE_CREATE_INFO; 1715 line_width.lineWidth = 1.0; 1716 1717 memset(&depth_bias, 0, sizeof(depth_bias)); 1718 depth_bias.sType = VK_STRUCTURE_TYPE_DYNAMIC_DEPTH_BIAS_STATE_CREATE_INFO; 1719 depth_bias.depthBias = 0.0f; 1720 depth_bias.depthBiasClamp = 0.0f; 1721 depth_bias.slopeScaledDepthBias = 0.0f; 1722 1723 memset(&blend, 0, sizeof(blend)); 1724 blend.sType = VK_STRUCTURE_TYPE_DYNAMIC_BLEND_STATE_CREATE_INFO; 1725 blend.blendConst[0] = 1.0f; 1726 blend.blendConst[1] = 1.0f; 1727 blend.blendConst[2] = 1.0f; 1728 blend.blendConst[3] = 1.0f; 1729 1730 memset(&depth_bounds, 0, sizeof(depth_bounds)); 1731 depth_bounds.sType = VK_STRUCTURE_TYPE_DYNAMIC_DEPTH_BOUNDS_STATE_CREATE_INFO; 1732 depth_bounds.minDepthBounds = 0.0f; 1733 depth_bounds.maxDepthBounds = 1.0f; 1734 1735 memset(&stencil, 0, sizeof(stencil)); 1736 stencil.sType = VK_STRUCTURE_TYPE_DYNAMIC_STENCIL_STATE_CREATE_INFO; 1737 stencil.stencilReference = 0; 1738 stencil.stencilCompareMask = 0xff; 1739 stencil.stencilWriteMask = 0xff; 1740 1741 err = vkCreateDynamicViewportState(demo->device, &viewport_create, &demo->dynamic_viewport); 1742 assert(!err); 1743 1744 err = vkCreateDynamicLineWidthState(demo->device, &line_width, &demo->dynamic_line_width); 1745 assert(!err); 1746 1747 err = vkCreateDynamicDepthBiasState(demo->device, &depth_bias, &demo->dynamic_depth_bias); 1748 assert(!err); 1749 1750 err = vkCreateDynamicBlendState(demo->device, 1751 &blend, &demo->dynamic_blend); 1752 assert(!err); 1753 1754 err = vkCreateDynamicDepthBoundsState(demo->device, 1755 &depth_bounds, &demo->dynamic_depth_bounds); 1756 assert(!err); 1757 1758 err = vkCreateDynamicStencilState(demo->device, 1759 &stencil, &stencil, &demo->dynamic_stencil); 1760 assert(!err); 1761} 1762 1763static void demo_prepare_descriptor_pool(struct demo *demo) 1764{ 1765 const VkDescriptorTypeCount type_counts[2] = { 1766 [0] = { 1767 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1768 .count = 1, 1769 }, 1770 [1] = { 1771 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1772 .count = DEMO_TEXTURE_COUNT, 1773 }, 1774 }; 1775 const VkDescriptorPoolCreateInfo descriptor_pool = { 1776 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 1777 .pNext = NULL, 1778 .count = 2, 1779 .pTypeCount = type_counts, 1780 }; 1781 VkResult U_ASSERT_ONLY err; 1782 1783 err = vkCreateDescriptorPool(demo->device, 1784 VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1, 1785 &descriptor_pool, &demo->desc_pool); 1786 assert(!err); 1787} 1788 1789static void demo_prepare_descriptor_set(struct demo *demo) 1790{ 1791 VkDescriptorInfo tex_descs[DEMO_TEXTURE_COUNT]; 1792 VkWriteDescriptorSet writes[2]; 1793 VkResult U_ASSERT_ONLY err; 1794 uint32_t i; 1795 1796 err = vkAllocDescriptorSets(demo->device, demo->desc_pool, 1797 VK_DESCRIPTOR_SET_USAGE_STATIC, 1798 1, &demo->desc_layout, 1799 &demo->desc_set); 1800 assert(!err); 1801 1802 memset(&tex_descs, 0, sizeof(tex_descs)); 1803 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1804 tex_descs[i].sampler = demo->textures[i].sampler; 1805 tex_descs[i].imageView = demo->textures[i].view; 1806 tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 1807 } 1808 1809 memset(&writes, 0, sizeof(writes)); 1810 1811 writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 1812 writes[0].destSet = demo->desc_set; 1813 writes[0].count = 1; 1814 writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 1815 writes[0].pDescriptors = &demo->uniform_data.desc; 1816 1817 writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 1818 writes[1].destSet = demo->desc_set; 1819 writes[1].destBinding = 1; 1820 writes[1].count = DEMO_TEXTURE_COUNT; 1821 writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 1822 writes[1].pDescriptors = tex_descs; 1823 1824 vkUpdateDescriptorSets(demo->device, 2, writes, 0, NULL); 1825} 1826 1827static void demo_prepare_framebuffers(struct demo *demo) 1828{ 1829 VkImageView attachments[2]; 1830 attachments[1] = demo->depth.view; 1831 1832 const VkFramebufferCreateInfo fb_info = { 1833 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 1834 .pNext = NULL, 1835 .renderPass = demo->render_pass, 1836 .attachmentCount = 2, 1837 .pAttachments = attachments, 1838 .width = demo->width, 1839 .height = demo->height, 1840 .layers = 1, 1841 }; 1842 VkResult U_ASSERT_ONLY err; 1843 uint32_t i; 1844 1845 for (i = 0; i < DEMO_BUFFER_COUNT; i++) { 1846 attachments[0] = demo->buffers[i].view; 1847 err = vkCreateFramebuffer(demo->device, &fb_info, &demo->framebuffers[i]); 1848 assert(!err); 1849 } 1850} 1851 1852static void demo_prepare(struct demo *demo) 1853{ 1854 VkResult U_ASSERT_ONLY err; 1855 1856 const VkCmdPoolCreateInfo cmd_pool_info = { 1857 .sType = VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO, 1858 .pNext = NULL, 1859 .queueFamilyIndex = demo->graphics_queue_node_index, 1860 .flags = 0, 1861 }; 1862 err = vkCreateCommandPool(demo->device, &cmd_pool_info, &demo->cmd_pool); 1863 assert(!err); 1864 1865 const VkCmdBufferCreateInfo cmd = { 1866 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO, 1867 .pNext = NULL, 1868 .cmdPool = demo->cmd_pool, 1869 .level = VK_CMD_BUFFER_LEVEL_PRIMARY, 1870 .flags = 0, 1871 }; 1872 1873 demo_prepare_buffers(demo); 1874 demo_prepare_depth(demo); 1875 demo_prepare_textures(demo); 1876 demo_prepare_cube_data_buffer(demo); 1877 1878 demo_prepare_descriptor_layout(demo); 1879 demo_prepare_render_pass(demo); 1880 demo_prepare_pipeline(demo); 1881 demo_prepare_dynamic_states(demo); 1882 1883 for (uint32_t i = 0; i < demo->swapchainImageCount; i++) { 1884 err = vkCreateCommandBuffer(demo->device, &cmd, &demo->buffers[i].cmd); 1885 assert(!err); 1886 } 1887 1888 demo_prepare_descriptor_pool(demo); 1889 demo_prepare_descriptor_set(demo); 1890 1891 demo_prepare_framebuffers(demo); 1892 1893 for (uint32_t i = 0; i < demo->swapchainImageCount; i++) { 1894 demo->current_buffer = i; 1895 demo_draw_build_cmd(demo, demo->buffers[i].cmd); 1896 } 1897 1898 /* 1899 * Prepare functions above may generate pipeline commands 1900 * that need to be flushed before beginning the render loop. 1901 */ 1902 demo_flush_init_cmd(demo); 1903 1904 demo->current_buffer = 0; 1905 demo->prepared = true; 1906} 1907 1908static void demo_cleanup(struct demo *demo) 1909{ 1910 uint32_t i; 1911 1912 demo->prepared = false; 1913 1914 for (i = 0; i < DEMO_BUFFER_COUNT; i++) { 1915 vkDestroyFramebuffer(demo->device, demo->framebuffers[i]); 1916 } 1917 vkFreeDescriptorSets(demo->device, demo->desc_pool, 1, &demo->desc_set); 1918 vkDestroyDescriptorPool(demo->device, demo->desc_pool); 1919 1920 vkDestroyDynamicViewportState(demo->device, demo->dynamic_viewport); 1921 vkDestroyDynamicLineWidthState(demo->device, demo->dynamic_line_width); 1922 vkDestroyDynamicDepthBiasState(demo->device, demo->dynamic_depth_bias); 1923 vkDestroyDynamicBlendState(demo->device, demo->dynamic_blend); 1924 vkDestroyDynamicDepthBoundsState(demo->device, demo->dynamic_depth_bounds); 1925 vkDestroyDynamicStencilState(demo->device, demo->dynamic_stencil); 1926 1927 vkDestroyPipeline(demo->device, demo->pipeline); 1928 vkDestroyPipelineCache(demo->device, demo->pipelineCache); 1929 vkDestroyRenderPass(demo->device, demo->render_pass); 1930 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout); 1931 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout); 1932 1933 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1934 vkDestroyImageView(demo->device, demo->textures[i].view); 1935 vkDestroyImage(demo->device, demo->textures[i].image); 1936 vkFreeMemory(demo->device, demo->textures[i].mem); 1937 vkDestroySampler(demo->device, demo->textures[i].sampler); 1938 } 1939 demo->fpDestroySwapchainKHR(demo->device, demo->swap_chain); 1940 1941 vkDestroyImageView(demo->device, demo->depth.view); 1942 vkDestroyImage(demo->device, demo->depth.image); 1943 vkFreeMemory(demo->device, demo->depth.mem); 1944 1945 vkDestroyBuffer(demo->device, demo->uniform_data.buf); 1946 vkFreeMemory(demo->device, demo->uniform_data.mem); 1947 1948 for (i = 0; i < demo->swapchainImageCount; i++) { 1949 vkDestroyImageView(demo->device, demo->buffers[i].view); 1950 vkDestroyCommandBuffer(demo->device, demo->buffers[i].cmd); 1951 } 1952 free(demo->buffers); 1953 1954 vkDestroyCommandPool(demo->device, demo->cmd_pool); 1955 vkDestroyDevice(demo->device); 1956 if (demo->validate) { 1957 demo->dbgDestroyMsgCallback(demo->inst, demo->msg_callback); 1958 } 1959 vkDestroyInstance(demo->inst); 1960 1961#ifndef _WIN32 1962 xcb_destroy_window(demo->connection, demo->window); 1963 xcb_disconnect(demo->connection); 1964#endif // _WIN32 1965} 1966 1967// On MS-Windows, make this a global, so it's available to WndProc() 1968struct demo demo; 1969 1970#ifdef _WIN32 1971static void demo_run(struct demo *demo) 1972{ 1973 if (!demo->prepared) 1974 return; 1975 // Wait for work to finish before updating MVP. 1976 vkDeviceWaitIdle(demo->device); 1977 demo_update_data_buffer(demo); 1978 1979 demo_draw(demo); 1980 1981 // Wait for work to finish before updating MVP. 1982 vkDeviceWaitIdle(demo->device); 1983 1984 demo->curFrame++; 1985 1986 if (demo->frameCount != INT_MAX && demo->curFrame == demo->frameCount) 1987 { 1988 demo->quit=true; 1989 demo_cleanup(demo); 1990 ExitProcess(0); 1991 } 1992 1993} 1994 1995// MS-Windows event handling function: 1996LRESULT CALLBACK WndProc(HWND hWnd, 1997 UINT uMsg, 1998 WPARAM wParam, 1999 LPARAM lParam) 2000{ 2001 switch(uMsg) 2002 { 2003 case WM_CLOSE: 2004 PostQuitMessage(0); 2005 break; 2006 case WM_PAINT: 2007 demo_run(&demo); 2008 return 0; 2009 default: 2010 break; 2011 } 2012 return (DefWindowProc(hWnd, uMsg, wParam, lParam)); 2013} 2014 2015static void demo_create_window(struct demo *demo) 2016{ 2017 WNDCLASSEX win_class; 2018 2019 // Initialize the window class structure: 2020 win_class.cbSize = sizeof(WNDCLASSEX); 2021 win_class.style = CS_HREDRAW | CS_VREDRAW; 2022 win_class.lpfnWndProc = WndProc; 2023 win_class.cbClsExtra = 0; 2024 win_class.cbWndExtra = 0; 2025 win_class.hInstance = demo->connection; // hInstance 2026 win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); 2027 win_class.hCursor = LoadCursor(NULL, IDC_ARROW); 2028 win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 2029 win_class.lpszMenuName = NULL; 2030 win_class.lpszClassName = demo->name; 2031 win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO); 2032 // Register window class: 2033 if (!RegisterClassEx(&win_class)) { 2034 // It didn't work, so try to give a useful error: 2035 printf("Unexpected error trying to start the application!\n"); 2036 fflush(stdout); 2037 exit(1); 2038 } 2039 // Create window with the registered class: 2040 RECT wr = { 0, 0, demo->width, demo->height }; 2041 AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); 2042 demo->window = CreateWindowEx(0, 2043 demo->name, // class name 2044 demo->name, // app name 2045 WS_OVERLAPPEDWINDOW | // window style 2046 WS_VISIBLE | 2047 WS_SYSMENU, 2048 100,100, // x/y coords 2049 wr.right-wr.left, // width 2050 wr.bottom-wr.top, // height 2051 NULL, // handle to parent 2052 NULL, // handle to menu 2053 demo->connection, // hInstance 2054 NULL); // no extra parameters 2055 if (!demo->window) { 2056 // It didn't work, so try to give a useful error: 2057 printf("Cannot create a window in which to draw!\n"); 2058 fflush(stdout); 2059 exit(1); 2060 } 2061} 2062#else // _WIN32 2063static void demo_handle_event(struct demo *demo, 2064 const xcb_generic_event_t *event) 2065{ 2066 uint8_t event_code = event->response_type & 0x7f; 2067 switch (event_code) { 2068 case XCB_EXPOSE: 2069 // TODO: Resize window 2070 break; 2071 case XCB_CLIENT_MESSAGE: 2072 if((*(xcb_client_message_event_t*)event).data.data32[0] == 2073 (*demo->atom_wm_delete_window).atom) { 2074 demo->quit = true; 2075 } 2076 break; 2077 case XCB_KEY_RELEASE: 2078 { 2079 const xcb_key_release_event_t *key = 2080 (const xcb_key_release_event_t *) event; 2081 2082 switch (key->detail) { 2083 case 0x9: // Escape 2084 demo->quit = true; 2085 break; 2086 case 0x71: // left arrow key 2087 demo->spin_angle += demo->spin_increment; 2088 break; 2089 case 0x72: // right arrow key 2090 demo->spin_angle -= demo->spin_increment; 2091 break; 2092 case 0x41: 2093 demo->pause = !demo->pause; 2094 break; 2095 } 2096 } 2097 break; 2098 default: 2099 break; 2100 } 2101} 2102 2103static void demo_run(struct demo *demo) 2104{ 2105 xcb_flush(demo->connection); 2106 2107 while (!demo->quit) { 2108 xcb_generic_event_t *event; 2109 2110 if (demo->pause) { 2111 event = xcb_wait_for_event(demo->connection); 2112 } else { 2113 event = xcb_poll_for_event(demo->connection); 2114 } 2115 if (event) { 2116 demo_handle_event(demo, event); 2117 free(event); 2118 } 2119 2120 // Wait for work to finish before updating MVP. 2121 vkDeviceWaitIdle(demo->device); 2122 demo_update_data_buffer(demo); 2123 2124 demo_draw(demo); 2125 2126 // Wait for work to finish before updating MVP. 2127 vkDeviceWaitIdle(demo->device); 2128 demo->curFrame++; 2129 if (demo->frameCount != INT_MAX && demo->curFrame == demo->frameCount) 2130 demo->quit = true; 2131 2132 } 2133} 2134 2135static void demo_create_window(struct demo *demo) 2136{ 2137 uint32_t value_mask, value_list[32]; 2138 2139 demo->window = xcb_generate_id(demo->connection); 2140 2141 value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 2142 value_list[0] = demo->screen->black_pixel; 2143 value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | 2144 XCB_EVENT_MASK_EXPOSURE; 2145 2146 xcb_create_window(demo->connection, 2147 XCB_COPY_FROM_PARENT, 2148 demo->window, demo->screen->root, 2149 0, 0, demo->width, demo->height, 0, 2150 XCB_WINDOW_CLASS_INPUT_OUTPUT, 2151 demo->screen->root_visual, 2152 value_mask, value_list); 2153 2154 /* Magic code that will send notification when window is destroyed */ 2155 xcb_intern_atom_cookie_t cookie = xcb_intern_atom(demo->connection, 1, 12, 2156 "WM_PROTOCOLS"); 2157 xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(demo->connection, cookie, 0); 2158 2159 xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW"); 2160 demo->atom_wm_delete_window = xcb_intern_atom_reply(demo->connection, cookie2, 0); 2161 2162 xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, 2163 demo->window, (*reply).atom, 4, 32, 1, 2164 &(*demo->atom_wm_delete_window).atom); 2165 free(reply); 2166 2167 xcb_map_window(demo->connection, demo->window); 2168 2169 // Force the x/y coordinates to 100,100 results are identical in consecutive runs 2170 const uint32_t coords[] = {100, 100}; 2171 xcb_configure_window(demo->connection, demo->window, 2172 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords); 2173} 2174#endif // _WIN32 2175 2176/* 2177 * Return 1 (true) if all layer names specified in check_names 2178 * can be found in given layer properties. 2179 */ 2180static VkBool32 demo_check_layers(uint32_t check_count, char **check_names, 2181 uint32_t layer_count, VkLayerProperties *layers) 2182{ 2183 for (uint32_t i = 0; i < check_count; i++) { 2184 VkBool32 found = 0; 2185 for (uint32_t j = 0; j < layer_count; j++) { 2186 if (!strcmp(check_names[i], layers[j].layerName)) { 2187 found = 1; 2188 } 2189 } 2190 if (!found) { 2191 fprintf(stderr, "Cannot find layer: %s\n", check_names[i]); 2192 return 0; 2193 } 2194 } 2195 return 1; 2196} 2197 2198static void demo_init_vk(struct demo *demo) 2199{ 2200 VkResult err; 2201 char *extension_names[64]; 2202 VkExtensionProperties *instance_extensions; 2203 VkPhysicalDevice *physical_devices; 2204 VkLayerProperties *instance_layers; 2205 VkLayerProperties *device_layers; 2206 uint32_t instance_extension_count = 0; 2207 uint32_t instance_layer_count = 0; 2208 uint32_t enabled_extension_count = 0; 2209 uint32_t enabled_layer_count = 0; 2210 2211 char *instance_validation_layers[] = { 2212 "Threading", 2213 "MemTracker", 2214 "ObjectTracker", 2215 "DrawState", 2216 "ParamChecker", 2217 "ShaderChecker", 2218 }; 2219 2220 char *device_validation_layers[] = { 2221 "Threading", 2222 "MemTracker", 2223 "ObjectTracker", 2224 "DrawState", 2225 "ParamChecker", 2226 "ShaderChecker", 2227 }; 2228 2229 /* Look for validation layers */ 2230 VkBool32 validation_found = 0; 2231 err = vkGetGlobalLayerProperties(&instance_layer_count, NULL); 2232 assert(!err); 2233 2234 instance_layers = malloc(sizeof(VkLayerProperties) * instance_layer_count); 2235 err = vkGetGlobalLayerProperties(&instance_layer_count, instance_layers); 2236 assert(!err); 2237 2238 if (demo->validate) { 2239 validation_found = demo_check_layers(ARRAY_SIZE(instance_validation_layers), instance_validation_layers, 2240 instance_layer_count, instance_layers); 2241 if (!validation_found) { 2242 ERR_EXIT("vkGetGlobalLayerProperties failed to find" 2243 "required validation layer.\n\n" 2244 "Please look at the Getting Started guide for additional " 2245 "information.\n", 2246 "vkCreateInstance Failure"); 2247 } 2248 enabled_layer_count = ARRAY_SIZE(instance_validation_layers); 2249 } 2250 2251 err = vkGetGlobalExtensionProperties(NULL, &instance_extension_count, NULL); 2252 assert(!err); 2253 2254 VkBool32 WSIextFound = 0; 2255 memset(extension_names, 0, sizeof(extension_names)); 2256 instance_extensions = malloc(sizeof(VkExtensionProperties) * instance_extension_count); 2257 err = vkGetGlobalExtensionProperties(NULL, &instance_extension_count, instance_extensions); 2258 assert(!err); 2259 for (uint32_t i = 0; i < instance_extension_count; i++) { 2260 if (!strcmp("VK_EXT_KHR_swapchain", instance_extensions[i].extName)) { 2261 WSIextFound = 1; 2262 extension_names[enabled_extension_count++] = "VK_EXT_KHR_swapchain"; 2263 } 2264 if (!strcmp(VK_DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extName)) { 2265 if (demo->validate) { 2266 extension_names[enabled_extension_count++] = VK_DEBUG_REPORT_EXTENSION_NAME; 2267 } 2268 } 2269 assert(enabled_extension_count < 64); 2270 } 2271 if (!WSIextFound) { 2272 ERR_EXIT("vkGetGlobalExtensionProperties failed to find the " 2273 "\"VK_EXT_KHR_swapchain\" extension.\n\nDo you have a compatible " 2274 "Vulkan installable client driver (ICD) installed?\nPlease " 2275 "look at the Getting Started guide for additional " 2276 "information.\n", 2277 "vkCreateInstance Failure"); 2278 } 2279 const VkApplicationInfo app = { 2280 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 2281 .pNext = NULL, 2282 .pAppName = APP_SHORT_NAME, 2283 .appVersion = 0, 2284 .pEngineName = APP_SHORT_NAME, 2285 .engineVersion = 0, 2286 .apiVersion = VK_API_VERSION, 2287 }; 2288 VkInstanceCreateInfo inst_info = { 2289 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 2290 .pNext = NULL, 2291 .pAppInfo = &app, 2292 .pAllocCb = NULL, 2293 .layerCount = enabled_layer_count, 2294 .ppEnabledLayerNames = (const char *const*) ((demo->validate) ? instance_validation_layers : NULL), 2295 .extensionCount = enabled_extension_count, 2296 .ppEnabledExtensionNames = (const char *const*) extension_names, 2297 }; 2298 const VkDeviceQueueCreateInfo queue = { 2299 .queueFamilyIndex = 0, 2300 .queueCount = 1, 2301 }; 2302 2303 uint32_t gpu_count; 2304 2305 err = vkCreateInstance(&inst_info, &demo->inst); 2306 if (err == VK_ERROR_INCOMPATIBLE_DRIVER) { 2307 ERR_EXIT("Cannot find a compatible Vulkan installable client driver " 2308 "(ICD).\n\nPlease look at the Getting Started guide for " 2309 "additional information.\n", 2310 "vkCreateInstance Failure"); 2311 } else if (err == VK_ERROR_INVALID_EXTENSION) { 2312 ERR_EXIT("Cannot find a specified extension library" 2313 ".\nMake sure your layers path is set appropriately\n", 2314 "vkCreateInstance Failure"); 2315 } else if (err) { 2316 ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan " 2317 "installable client driver (ICD) installed?\nPlease look at " 2318 "the Getting Started guide for additional information.\n", 2319 "vkCreateInstance Failure"); 2320 } 2321 2322 free(instance_layers); 2323 free(instance_extensions); 2324 2325 /* Make initial call to query gpu_count, then second call for gpu info*/ 2326 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL); 2327 assert(!err && gpu_count > 0); 2328 physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count); 2329 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, physical_devices); 2330 assert(!err); 2331 /* For cube demo we just grab the first physical device */ 2332 demo->gpu = physical_devices[0]; 2333 free(physical_devices); 2334 2335 /* Look for validation layers */ 2336 validation_found = 0; 2337 enabled_layer_count = 0; 2338 uint32_t device_layer_count = 0; 2339 err = vkGetPhysicalDeviceLayerProperties(demo->gpu, &device_layer_count, NULL); 2340 assert(!err); 2341 2342 device_layers = malloc(sizeof(VkLayerProperties) * device_layer_count); 2343 err = vkGetPhysicalDeviceLayerProperties(demo->gpu, &device_layer_count, device_layers); 2344 assert(!err); 2345 2346 if (demo->validate) { 2347 validation_found = demo_check_layers(ARRAY_SIZE(device_validation_layers), device_validation_layers, 2348 device_layer_count, device_layers); 2349 if (!validation_found) { 2350 ERR_EXIT("vkGetPhysicalDeviceLayerProperties failed to find" 2351 "a required validation layer.\n\n" 2352 "Please look at the Getting Started guide for additional " 2353 "information.\n", 2354 "vkCreateDevice Failure"); 2355 } 2356 enabled_layer_count = ARRAY_SIZE(device_validation_layers); 2357 } 2358 2359 uint32_t device_extension_count = 0; 2360 VkExtensionProperties *device_extensions = NULL; 2361 err = vkGetPhysicalDeviceExtensionProperties( 2362 demo->gpu, NULL, &device_extension_count, NULL); 2363 assert(!err); 2364 2365 WSIextFound = 0; 2366 enabled_extension_count = 0; 2367 memset(extension_names, 0, sizeof(extension_names)); 2368 device_extensions = malloc(sizeof(VkExtensionProperties) * device_extension_count); 2369 err = vkGetPhysicalDeviceExtensionProperties( 2370 demo->gpu, NULL, &device_extension_count, device_extensions); 2371 assert(!err); 2372 2373 for (uint32_t i = 0; i < device_extension_count; i++) { 2374 if (!strcmp("VK_EXT_KHR_device_swapchain", device_extensions[i].extName)) { 2375 WSIextFound = 1; 2376 extension_names[enabled_extension_count++] = "VK_EXT_KHR_device_swapchain"; 2377 } 2378 assert(enabled_extension_count < 64); 2379 } 2380 if (!WSIextFound) { 2381 ERR_EXIT("vkGetPhysicalDeviceExtensionProperties failed to find the " 2382 "\"VK_EXT_KHR_device_swapchain\" extension.\n\nDo you have a compatible " 2383 "Vulkan installable client driver (ICD) installed?\nPlease " 2384 "look at the Getting Started guide for additional " 2385 "information.\n", 2386 "vkCreateInstance Failure"); 2387 } 2388 2389 VkDeviceCreateInfo device = { 2390 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 2391 .pNext = NULL, 2392 .queueRecordCount = 1, 2393 .pRequestedQueues = &queue, 2394 .layerCount = enabled_layer_count, 2395 .ppEnabledLayerNames = (const char *const*) ((demo->validate) ? device_validation_layers : NULL), 2396 .extensionCount = enabled_extension_count, 2397 .ppEnabledExtensionNames = (const char *const*) extension_names, 2398 }; 2399 2400 if (demo->validate) { 2401 demo->dbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback) vkGetInstanceProcAddr(demo->inst, "vkDbgCreateMsgCallback"); 2402 demo->dbgDestroyMsgCallback = (PFN_vkDbgDestroyMsgCallback) vkGetInstanceProcAddr(demo->inst, "vkDbgDestroyMsgCallback"); 2403 if (!demo->dbgCreateMsgCallback) { 2404 ERR_EXIT("GetProcAddr: Unable to find vkDbgCreateMsgCallback\n", 2405 "vkGetProcAddr Failure"); 2406 } 2407 if (!demo->dbgDestroyMsgCallback) { 2408 ERR_EXIT("GetProcAddr: Unable to find vkDbgDestroyMsgCallback\n", 2409 "vkGetProcAddr Failure"); 2410 } 2411 demo->dbgBreakCallback = (PFN_vkDbgMsgCallback) vkGetInstanceProcAddr(demo->inst, "vkDbgBreakCallback"); 2412 if (!demo->dbgBreakCallback) { 2413 ERR_EXIT("GetProcAddr: Unable to find vkDbgBreakCallback\n", 2414 "vkGetProcAddr Failure"); 2415 } 2416 2417 PFN_vkDbgMsgCallback callback; 2418 2419 if (!demo->use_break) { 2420 callback = dbgFunc; 2421 } else { 2422 callback = demo->dbgBreakCallback; 2423 } 2424 err = demo->dbgCreateMsgCallback( 2425 demo->inst, 2426 VK_DBG_REPORT_ERROR_BIT | VK_DBG_REPORT_WARN_BIT, 2427 callback, NULL, 2428 &demo->msg_callback); 2429 switch (err) { 2430 case VK_SUCCESS: 2431 break; 2432 case VK_ERROR_OUT_OF_HOST_MEMORY: 2433 ERR_EXIT("dbgCreateMsgCallback: out of host memory\n", 2434 "dbgCreateMsgCallback Failure"); 2435 break; 2436 default: 2437 ERR_EXIT("dbgCreateMsgCallback: unknown failure\n", 2438 "dbgCreateMsgCallback Failure"); 2439 break; 2440 } 2441 } 2442 2443 err = vkCreateDevice(demo->gpu, &device, &demo->device); 2444 assert(!err); 2445 2446 free(device_layers); 2447 2448 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR); 2449 GET_DEVICE_PROC_ADDR(demo->device, GetSurfacePropertiesKHR); 2450 GET_DEVICE_PROC_ADDR(demo->device, GetSurfaceFormatsKHR); 2451 GET_DEVICE_PROC_ADDR(demo->device, GetSurfacePresentModesKHR); 2452 GET_DEVICE_PROC_ADDR(demo->device, CreateSwapchainKHR); 2453 GET_DEVICE_PROC_ADDR(demo->device, CreateSwapchainKHR); 2454 GET_DEVICE_PROC_ADDR(demo->device, DestroySwapchainKHR); 2455 GET_DEVICE_PROC_ADDR(demo->device, GetSwapchainImagesKHR); 2456 GET_DEVICE_PROC_ADDR(demo->device, AcquireNextImageKHR); 2457 GET_DEVICE_PROC_ADDR(demo->device, QueuePresentKHR); 2458 2459 err = vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props); 2460 assert(!err); 2461 2462 /* Call with NULL data to get count */ 2463 err = vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, NULL); 2464 assert(!err); 2465 assert(demo->queue_count >= 1); 2466 2467 demo->queue_props = (VkQueueFamilyProperties *) malloc(demo->queue_count * sizeof(VkQueueFamilyProperties)); 2468 err = vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, demo->queue_props); 2469 assert(!err); 2470 assert(demo->queue_count >= 1); 2471} 2472 2473static void demo_init_vk_wsi(struct demo *demo) 2474{ 2475 VkResult err; 2476 uint32_t i; 2477 2478 // Construct the WSI surface description: 2479 demo->surface_description.sType = VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_KHR; 2480 demo->surface_description.pNext = NULL; 2481#ifdef _WIN32 2482 demo->surface_description.platform = VK_PLATFORM_WIN32_KHR; 2483 demo->surface_description.pPlatformHandle = demo->connection; 2484 demo->surface_description.pPlatformWindow = demo->window; 2485#else // _WIN32 2486 demo->platform_handle_xcb.connection = demo->connection; 2487 demo->platform_handle_xcb.root = demo->screen->root; 2488 demo->surface_description.platform = VK_PLATFORM_XCB_KHR; 2489 demo->surface_description.pPlatformHandle = &demo->platform_handle_xcb; 2490 demo->surface_description.pPlatformWindow = &demo->window; 2491#endif // _WIN32 2492 2493 // Iterate over each queue to learn whether it supports presenting to WSI: 2494 VkBool32* supportsPresent = (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32)); 2495 for (i = 0; i < demo->queue_count; i++) { 2496 demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, 2497 (VkSurfaceDescriptionKHR *) &demo->surface_description, 2498 &supportsPresent[i]); 2499 } 2500 2501 // Search for a graphics and a present queue in the array of queue 2502 // families, try to find one that supports both 2503 uint32_t graphicsQueueNodeIndex = UINT32_MAX; 2504 uint32_t presentQueueNodeIndex = UINT32_MAX; 2505 for (i = 0; i < demo->queue_count; i++) { 2506 if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { 2507 if (graphicsQueueNodeIndex == UINT32_MAX) { 2508 graphicsQueueNodeIndex = i; 2509 } 2510 2511 if (supportsPresent[i] == VK_TRUE) { 2512 graphicsQueueNodeIndex = i; 2513 presentQueueNodeIndex = i; 2514 break; 2515 } 2516 } 2517 } 2518 if (presentQueueNodeIndex == UINT32_MAX) { 2519 // If didn't find a queue that supports both graphics and present, then 2520 // find a separate present queue. 2521 for (uint32_t i = 0; i < demo->queue_count; ++i) { 2522 if (supportsPresent[i] == VK_TRUE) { 2523 presentQueueNodeIndex = i; 2524 break; 2525 } 2526 } 2527 } 2528 free(supportsPresent); 2529 2530 // Generate error if could not find both a graphics and a present queue 2531 if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) { 2532 ERR_EXIT("Could not find a graphics and a present queue\n", 2533 "WSI Initialization Failure"); 2534 } 2535 2536 // TODO: Add support for separate queues, including presentation, 2537 // synchronization, and appropriate tracking for QueueSubmit 2538 // While it is possible for an application to use a separate graphics and a 2539 // present queues, this demo program assumes it is only using one: 2540 if (graphicsQueueNodeIndex != presentQueueNodeIndex) { 2541 ERR_EXIT("Could not find a common graphics and a present queue\n", 2542 "WSI Initialization Failure"); 2543 } 2544 2545 demo->graphics_queue_node_index = graphicsQueueNodeIndex; 2546 2547 err = vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 2548 0, &demo->queue); 2549 assert(!err); 2550 2551 // Get the list of VkFormat's that are supported: 2552 uint32_t formatCount; 2553 err = demo->fpGetSurfaceFormatsKHR(demo->device, 2554 (VkSurfaceDescriptionKHR *) &demo->surface_description, 2555 &formatCount, NULL); 2556 assert(!err); 2557 VkSurfaceFormatKHR *surfFormats = 2558 (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); 2559 err = demo->fpGetSurfaceFormatsKHR(demo->device, 2560 (VkSurfaceDescriptionKHR *) &demo->surface_description, 2561 &formatCount, surfFormats); 2562 assert(!err); 2563 // If the format list includes just one entry of VK_FORMAT_UNDEFINED, 2564 // the surface has no preferred format. Otherwise, at least one 2565 // supported format will be returned. 2566 if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) 2567 { 2568 demo->format = VK_FORMAT_B8G8R8A8_UNORM; 2569 } 2570 else 2571 { 2572 assert(formatCount >= 1); 2573 demo->format = surfFormats[0].format; 2574 } 2575 demo->color_space = surfFormats[0].colorSpace; 2576 2577 demo->quit = false; 2578 demo->curFrame = 0; 2579 2580 // Get Memory information and properties 2581 err = vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties); 2582 assert(!err); 2583} 2584 2585static void demo_init_connection(struct demo *demo) 2586{ 2587#ifndef _WIN32 2588 const xcb_setup_t *setup; 2589 xcb_screen_iterator_t iter; 2590 int scr; 2591 2592 demo->connection = xcb_connect(NULL, &scr); 2593 if (demo->connection == NULL) { 2594 printf("Cannot find a compatible Vulkan installable client driver " 2595 "(ICD).\nExiting ...\n"); 2596 fflush(stdout); 2597 exit(1); 2598 } 2599 2600 setup = xcb_get_setup(demo->connection); 2601 iter = xcb_setup_roots_iterator(setup); 2602 while (scr-- > 0) 2603 xcb_screen_next(&iter); 2604 2605 demo->screen = iter.data; 2606#endif // _WIN32 2607} 2608 2609static void demo_init(struct demo *demo, int argc, char **argv) 2610{ 2611 vec3 eye = {0.0f, 3.0f, 5.0f}; 2612 vec3 origin = {0, 0, 0}; 2613 vec3 up = {0.0f, 1.0f, 0.0}; 2614 2615 memset(demo, 0, sizeof(*demo)); 2616 demo->frameCount = INT_MAX; 2617 2618 for (int i = 1; i < argc; i++) { 2619 if (strcmp(argv[i], "--use_staging") == 0) { 2620 demo->use_staging_buffer = true; 2621 continue; 2622 } 2623 if (strcmp(argv[i], "--use_glsl") == 0) { 2624 demo->use_glsl = true; 2625 continue; 2626 } 2627 if (strcmp(argv[i], "--break") == 0) { 2628 demo->use_break = true; 2629 continue; 2630 } 2631 if (strcmp(argv[i], "--validate") == 0) { 2632 demo->validate = true; 2633 continue; 2634 } 2635 if (strcmp(argv[i], "--c") == 0 && 2636 demo->frameCount == INT_MAX && 2637 i < argc-1 && 2638 sscanf(argv[i+1],"%d", &demo->frameCount) == 1 && 2639 demo->frameCount >= 0) 2640 { 2641 i++; 2642 continue; 2643 } 2644 2645 fprintf(stderr, "Usage:\n %s [--use_staging] [--validate] [--break] [--c <framecount>]\n", APP_SHORT_NAME); 2646 fflush(stderr); 2647 exit(1); 2648 } 2649 2650 demo_init_connection(demo); 2651 demo_init_vk(demo); 2652 2653 demo->width = 500; 2654 demo->height = 500; 2655 2656 demo->spin_angle = 0.01f; 2657 demo->spin_increment = 0.01f; 2658 demo->pause = false; 2659 2660 mat4x4_perspective(demo->projection_matrix, (float)degreesToRadians(45.0f), 1.0f, 0.1f, 100.0f); 2661 mat4x4_look_at(demo->view_matrix, eye, origin, up); 2662 mat4x4_identity(demo->model_matrix); 2663} 2664 2665 2666#ifdef _WIN32 2667extern int __getmainargs( 2668 int * _Argc, 2669 char *** _Argv, 2670 char *** _Env, 2671 int _DoWildCard, 2672 int * new_mode); 2673 2674int WINAPI WinMain(HINSTANCE hInstance, 2675 HINSTANCE hPrevInstance, 2676 LPSTR pCmdLine, 2677 int nCmdShow) 2678{ 2679 MSG msg; // message 2680 bool done; // flag saying when app is complete 2681 int argc; 2682 char** argv; 2683 char** env; 2684 int new_mode = 0; 2685 2686 __getmainargs(&argc,&argv,&env,0,&new_mode); 2687 2688 demo_init(&demo, argc, argv); 2689 demo.connection = hInstance; 2690 strncpy(demo.name, "cube", APP_NAME_STR_LEN); 2691 demo_create_window(&demo); 2692 demo_init_vk_wsi(&demo); 2693 2694 demo_prepare(&demo); 2695 2696 done = false; //initialize loop condition variable 2697 /* main message loop*/ 2698 while(!done) 2699 { 2700 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); 2701 if (msg.message == WM_QUIT) //check for a quit message 2702 { 2703 done = true; //if found, quit app 2704 } 2705 else 2706 { 2707 /* Translate and dispatch to event queue*/ 2708 TranslateMessage(&msg); 2709 DispatchMessage(&msg); 2710 } 2711 } 2712 2713 demo_cleanup(&demo); 2714 2715 return (int) msg.wParam; 2716} 2717#else // _WIN32 2718int main(int argc, char **argv) 2719{ 2720 struct demo demo; 2721 2722 demo_init(&demo, argc, argv); 2723 demo_create_window(&demo); 2724 demo_init_vk_wsi(&demo); 2725 2726 demo_prepare(&demo); 2727 demo_run(&demo); 2728 2729 demo_cleanup(&demo); 2730 2731 return 0; 2732} 2733#endif // _WIN32 2734