cube.c revision 71ed0bbee1985e6fe3c47e043bc1f66cc59b437b
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 <olv@lunarg.com> 19 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> 20 * Author: Ian Elliott <ian@LunarG.com> 21 * Author: Jon Ashburn <jon@lunarg.com> 22 */ 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#include <signal.h> 31#ifdef __linux__ 32#include <X11/Xutil.h> 33#endif 34 35#ifdef _WIN32 36#pragma comment(linker, "/subsystem:windows") 37#define APP_NAME_STR_LEN 80 38#endif // _WIN32 39 40#include <vulkan/vulkan.h> 41 42#include <vulkan/vk_sdk_platform.h> 43#include "linmath.h" 44 45#define DEMO_TEXTURE_COUNT 1 46#define APP_SHORT_NAME "cube" 47#define APP_LONG_NAME "The Vulkan Cube Demo Program" 48 49#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 50 51#if defined(NDEBUG) && defined(__GNUC__) 52#define U_ASSERT_ONLY __attribute__((unused)) 53#else 54#define U_ASSERT_ONLY 55#endif 56 57#ifdef _WIN32 58#define ERR_EXIT(err_msg, err_class) \ 59 do { \ 60 MessageBox(NULL, err_msg, err_class, MB_OK); \ 61 exit(1); \ 62 } while (0) 63 64#elif defined __ANDROID__ 65#include <android/log.h> 66#define ERR_EXIT(err_msg, err_class) \ 67 do { \ 68 ((void)__android_log_print(ANDROID_LOG_INFO, "Cube", err_msg)); \ 69 exit(1); \ 70 } while (0) 71#else 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 79 80#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \ 81 { \ 82 demo->fp##entrypoint = \ 83 (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \ 84 if (demo->fp##entrypoint == NULL) { \ 85 ERR_EXIT("vkGetInstanceProcAddr failed to find vk" #entrypoint, \ 86 "vkGetInstanceProcAddr Failure"); \ 87 } \ 88 } 89 90static PFN_vkGetDeviceProcAddr g_gdpa = NULL; 91 92#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \ 93 { \ 94 if (!g_gdpa) \ 95 g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr( \ 96 demo->inst, "vkGetDeviceProcAddr"); \ 97 demo->fp##entrypoint = \ 98 (PFN_vk##entrypoint)g_gdpa(dev, "vk" #entrypoint); \ 99 if (demo->fp##entrypoint == NULL) { \ 100 ERR_EXIT("vkGetDeviceProcAddr failed to find vk" #entrypoint, \ 101 "vkGetDeviceProcAddr Failure"); \ 102 } \ 103 } 104 105/* 106 * structure to track all objects related to a texture. 107 */ 108struct texture_object { 109 VkSampler sampler; 110 111 VkImage image; 112 VkImageLayout imageLayout; 113 114 VkMemoryAllocateInfo mem_alloc; 115 VkDeviceMemory mem; 116 VkImageView view; 117 int32_t tex_width, tex_height; 118}; 119 120static char *tex_files[] = {"lunarg.ppm"}; 121 122static int validation_error = 0; 123 124struct vkcube_vs_uniform { 125 // Must start with MVP 126 float mvp[4][4]; 127 float position[12 * 3][4]; 128 float color[12 * 3][4]; 129}; 130 131struct vktexcube_vs_uniform { 132 // Must start with MVP 133 float mvp[4][4]; 134 float position[12 * 3][4]; 135 float attr[12 * 3][4]; 136}; 137 138//-------------------------------------------------------------------------------------- 139// Mesh and VertexFormat Data 140//-------------------------------------------------------------------------------------- 141// clang-format off 142struct Vertex 143{ 144 float posX, posY, posZ, posW; // Position data 145 float r, g, b, a; // Color 146}; 147 148struct VertexPosTex 149{ 150 float posX, posY, posZ, posW; // Position data 151 float u, v, s, t; // Texcoord 152}; 153 154#define XYZ1(_x_, _y_, _z_) (_x_), (_y_), (_z_), 1.f 155#define UV(_u_, _v_) (_u_), (_v_), 0.f, 1.f 156 157static const float g_vertex_buffer_data[] = { 158 -1.0f,-1.0f,-1.0f, // -X side 159 -1.0f,-1.0f, 1.0f, 160 -1.0f, 1.0f, 1.0f, 161 -1.0f, 1.0f, 1.0f, 162 -1.0f, 1.0f,-1.0f, 163 -1.0f,-1.0f,-1.0f, 164 165 -1.0f,-1.0f,-1.0f, // -Z side 166 1.0f, 1.0f,-1.0f, 167 1.0f,-1.0f,-1.0f, 168 -1.0f,-1.0f,-1.0f, 169 -1.0f, 1.0f,-1.0f, 170 1.0f, 1.0f,-1.0f, 171 172 -1.0f,-1.0f,-1.0f, // -Y side 173 1.0f,-1.0f,-1.0f, 174 1.0f,-1.0f, 1.0f, 175 -1.0f,-1.0f,-1.0f, 176 1.0f,-1.0f, 1.0f, 177 -1.0f,-1.0f, 1.0f, 178 179 -1.0f, 1.0f,-1.0f, // +Y side 180 -1.0f, 1.0f, 1.0f, 181 1.0f, 1.0f, 1.0f, 182 -1.0f, 1.0f,-1.0f, 183 1.0f, 1.0f, 1.0f, 184 1.0f, 1.0f,-1.0f, 185 186 1.0f, 1.0f,-1.0f, // +X side 187 1.0f, 1.0f, 1.0f, 188 1.0f,-1.0f, 1.0f, 189 1.0f,-1.0f, 1.0f, 190 1.0f,-1.0f,-1.0f, 191 1.0f, 1.0f,-1.0f, 192 193 -1.0f, 1.0f, 1.0f, // +Z side 194 -1.0f,-1.0f, 1.0f, 195 1.0f, 1.0f, 1.0f, 196 -1.0f,-1.0f, 1.0f, 197 1.0f,-1.0f, 1.0f, 198 1.0f, 1.0f, 1.0f, 199}; 200 201static const float g_uv_buffer_data[] = { 202 0.0f, 0.0f, // -X side 203 1.0f, 0.0f, 204 1.0f, 1.0f, 205 1.0f, 1.0f, 206 0.0f, 1.0f, 207 0.0f, 0.0f, 208 209 1.0f, 0.0f, // -Z side 210 0.0f, 1.0f, 211 0.0f, 0.0f, 212 1.0f, 0.0f, 213 1.0f, 1.0f, 214 0.0f, 1.0f, 215 216 1.0f, 1.0f, // -Y side 217 1.0f, 0.0f, 218 0.0f, 0.0f, 219 1.0f, 1.0f, 220 0.0f, 0.0f, 221 0.0f, 1.0f, 222 223 1.0f, 1.0f, // +Y side 224 0.0f, 1.0f, 225 0.0f, 0.0f, 226 1.0f, 1.0f, 227 0.0f, 0.0f, 228 1.0f, 0.0f, 229 230 1.0f, 1.0f, // +X side 231 0.0f, 1.0f, 232 0.0f, 0.0f, 233 0.0f, 0.0f, 234 1.0f, 0.0f, 235 1.0f, 1.0f, 236 237 0.0f, 1.0f, // +Z side 238 0.0f, 0.0f, 239 1.0f, 1.0f, 240 0.0f, 0.0f, 241 1.0f, 0.0f, 242 1.0f, 1.0f, 243}; 244// clang-format on 245 246void dumpMatrix(const char *note, mat4x4 MVP) { 247 int i; 248 249 printf("%s: \n", note); 250 for (i = 0; i < 4; i++) { 251 printf("%f, %f, %f, %f\n", MVP[i][0], MVP[i][1], MVP[i][2], MVP[i][3]); 252 } 253 printf("\n"); 254 fflush(stdout); 255} 256 257void dumpVec4(const char *note, vec4 vector) { 258 printf("%s: \n", note); 259 printf("%f, %f, %f, %f\n", vector[0], vector[1], vector[2], vector[3]); 260 printf("\n"); 261 fflush(stdout); 262} 263 264VKAPI_ATTR VkBool32 VKAPI_CALL 265dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, 266 uint64_t srcObject, size_t location, int32_t msgCode, 267 const char *pLayerPrefix, const char *pMsg, void *pUserData) { 268 char *message = (char *)malloc(strlen(pMsg) + 100); 269 270 assert(message); 271 272 if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { 273 sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, 274 pMsg); 275 validation_error = 1; 276 } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { 277 // We know that we're submitting queues without fences, ignore this 278 // warning 279 if (strstr(pMsg, 280 "vkQueueSubmit parameter, VkFence fence, is null pointer")) { 281 return false; 282 } 283 sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, 284 pMsg); 285 validation_error = 1; 286 } else { 287 validation_error = 1; 288 return false; 289 } 290 291#ifdef _WIN32 292 MessageBox(NULL, message, "Alert", MB_OK); 293#else 294 printf("%s\n", message); 295 fflush(stdout); 296#endif 297 free(message); 298 299 /* 300 * false indicates that layer should not bail-out of an 301 * API call that had validation failures. This may mean that the 302 * app dies inside the driver due to invalid parameter(s). 303 * That's what would happen without validation layers, so we'll 304 * keep that behavior here. 305 */ 306 return false; 307} 308 309VKAPI_ATTR VkBool32 VKAPI_CALL 310BreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, 311 uint64_t srcObject, size_t location, int32_t msgCode, 312 const char *pLayerPrefix, const char *pMsg, 313 void *pUserData) { 314#ifndef WIN32 315 raise(SIGTRAP); 316#else 317 DebugBreak(); 318#endif 319 320 return false; 321} 322 323typedef struct _SwapchainBuffers { 324 VkImage image; 325 VkCommandBuffer cmd; 326 VkImageView view; 327} SwapchainBuffers; 328 329struct demo { 330#if defined(VK_USE_PLATFORM_WIN32_KHR) 331#define APP_NAME_STR_LEN 80 332 HINSTANCE connection; // hInstance - Windows Instance 333 char name[APP_NAME_STR_LEN]; // Name to put on the window/icon 334 HWND window; // hWnd - window handle 335#elif defined(VK_USE_PLATFORM_XLIB_KHR) 336 Display* display; 337 Window xlib_window; 338 Atom xlib_wm_delete_window; 339#elif defined(VK_USE_PLATFORM_XCB_KHR) 340 xcb_connection_t *connection; 341 xcb_screen_t *screen; 342 xcb_window_t xcb_window; 343 xcb_intern_atom_reply_t *atom_wm_delete_window; 344#elif defined(VK_USE_PLATFORM_ANDROID_KHR) 345 ANativeWindow* window; 346#endif 347 VkSurfaceKHR surface; 348 bool prepared; 349 bool use_staging_buffer; 350 bool use_xlib; 351 352 VkInstance inst; 353 VkPhysicalDevice gpu; 354 VkDevice device; 355 VkQueue queue; 356 uint32_t graphics_queue_node_index; 357 VkPhysicalDeviceProperties gpu_props; 358 VkQueueFamilyProperties *queue_props; 359 VkPhysicalDeviceMemoryProperties memory_properties; 360 361 uint32_t enabled_extension_count; 362 uint32_t enabled_layer_count; 363 char *extension_names[64]; 364 char *device_validation_layers[64]; 365 366 int width, height; 367 VkFormat format; 368 VkColorSpaceKHR color_space; 369 370 PFN_vkGetPhysicalDeviceSurfaceSupportKHR 371 fpGetPhysicalDeviceSurfaceSupportKHR; 372 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR 373 fpGetPhysicalDeviceSurfaceCapabilitiesKHR; 374 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR 375 fpGetPhysicalDeviceSurfaceFormatsKHR; 376 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR 377 fpGetPhysicalDeviceSurfacePresentModesKHR; 378 PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR; 379 PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR; 380 PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR; 381 PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR; 382 PFN_vkQueuePresentKHR fpQueuePresentKHR; 383 uint32_t swapchainImageCount; 384 VkSwapchainKHR swapchain; 385 SwapchainBuffers *buffers; 386 387 VkCommandPool cmd_pool; 388 389 struct { 390 VkFormat format; 391 392 VkImage image; 393 VkMemoryAllocateInfo mem_alloc; 394 VkDeviceMemory mem; 395 VkImageView view; 396 } depth; 397 398 struct texture_object textures[DEMO_TEXTURE_COUNT]; 399 400 struct { 401 VkBuffer buf; 402 VkMemoryAllocateInfo mem_alloc; 403 VkDeviceMemory mem; 404 VkDescriptorBufferInfo buffer_info; 405 } uniform_data; 406 407 VkCommandBuffer cmd; // Buffer for initialization commands 408 VkPipelineLayout pipeline_layout; 409 VkDescriptorSetLayout desc_layout; 410 VkPipelineCache pipelineCache; 411 VkRenderPass render_pass; 412 VkPipeline pipeline; 413 414 mat4x4 projection_matrix; 415 mat4x4 view_matrix; 416 mat4x4 model_matrix; 417 418 float spin_angle; 419 float spin_increment; 420 bool pause; 421 422 VkShaderModule vert_shader_module; 423 VkShaderModule frag_shader_module; 424 425 VkDescriptorPool desc_pool; 426 VkDescriptorSet desc_set; 427 428 VkFramebuffer *framebuffers; 429 430 bool quit; 431 int32_t curFrame; 432 int32_t frameCount; 433 bool validate; 434 bool use_break; 435 PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback; 436 PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback; 437 VkDebugReportCallbackEXT msg_callback; 438 PFN_vkDebugReportMessageEXT DebugReportMessage; 439 440 uint32_t current_buffer; 441 uint32_t queue_count; 442}; 443 444// Forward declaration: 445static void demo_resize(struct demo *demo); 446 447static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits, 448 VkFlags requirements_mask, 449 uint32_t *typeIndex) { 450 // Search memtypes to find first index with those properties 451 for (uint32_t i = 0; i < 32; i++) { 452 if ((typeBits & 1) == 1) { 453 // Type is available, does it match user properties? 454 if ((demo->memory_properties.memoryTypes[i].propertyFlags & 455 requirements_mask) == requirements_mask) { 456 *typeIndex = i; 457 return true; 458 } 459 } 460 typeBits >>= 1; 461 } 462 // No memory types matched, return failure 463 return false; 464} 465 466static void demo_flush_init_cmd(struct demo *demo) { 467 VkResult U_ASSERT_ONLY err; 468 469 if (demo->cmd == VK_NULL_HANDLE) 470 return; 471 472 err = vkEndCommandBuffer(demo->cmd); 473 assert(!err); 474 475 const VkCommandBuffer cmd_bufs[] = {demo->cmd}; 476 VkFence nullFence = VK_NULL_HANDLE; 477 VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 478 .pNext = NULL, 479 .waitSemaphoreCount = 0, 480 .pWaitSemaphores = NULL, 481 .pWaitDstStageMask = NULL, 482 .commandBufferCount = 1, 483 .pCommandBuffers = cmd_bufs, 484 .signalSemaphoreCount = 0, 485 .pSignalSemaphores = NULL}; 486 487 err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence); 488 assert(!err); 489 490 err = vkQueueWaitIdle(demo->queue); 491 assert(!err); 492 493 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, cmd_bufs); 494 demo->cmd = VK_NULL_HANDLE; 495} 496 497static void demo_set_image_layout(struct demo *demo, VkImage image, 498 VkImageAspectFlags aspectMask, 499 VkImageLayout old_image_layout, 500 VkImageLayout new_image_layout, 501 VkAccessFlagBits srcAccessMask) { 502 VkResult U_ASSERT_ONLY err; 503 504 if (demo->cmd == VK_NULL_HANDLE) { 505 const VkCommandBufferAllocateInfo cmd = { 506 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 507 .pNext = NULL, 508 .commandPool = demo->cmd_pool, 509 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 510 .commandBufferCount = 1, 511 }; 512 513 err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->cmd); 514 assert(!err); 515 516 VkCommandBufferInheritanceInfo cmd_buf_hinfo = { 517 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 518 .pNext = NULL, 519 .renderPass = VK_NULL_HANDLE, 520 .subpass = 0, 521 .framebuffer = VK_NULL_HANDLE, 522 .occlusionQueryEnable = VK_FALSE, 523 .queryFlags = 0, 524 .pipelineStatistics = 0, 525 }; 526 VkCommandBufferBeginInfo cmd_buf_info = { 527 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 528 .pNext = NULL, 529 .flags = 0, 530 .pInheritanceInfo = &cmd_buf_hinfo, 531 }; 532 err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info); 533 assert(!err); 534 } 535 536 VkImageMemoryBarrier image_memory_barrier = { 537 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 538 .pNext = NULL, 539 .srcAccessMask = srcAccessMask, 540 .dstAccessMask = 0, 541 .oldLayout = old_image_layout, 542 .newLayout = new_image_layout, 543 .image = image, 544 .subresourceRange = {aspectMask, 0, 1, 0, 1}}; 545 546 if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { 547 /* Make sure anything that was copying from this image has completed */ 548 image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; 549 } 550 551 if (new_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { 552 image_memory_barrier.dstAccessMask = 553 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 554 } 555 556 if (new_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { 557 image_memory_barrier.dstAccessMask = 558 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; 559 } 560 561 if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 562 /* Make sure any Copy or CPU writes to image are flushed */ 563 image_memory_barrier.dstAccessMask = 564 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; 565 } 566 567 VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier; 568 569 VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 570 VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 571 572 vkCmdPipelineBarrier(demo->cmd, src_stages, dest_stages, 0, 0, NULL, 0, 573 NULL, 1, pmemory_barrier); 574} 575 576static void demo_draw_build_cmd(struct demo *demo, VkCommandBuffer cmd_buf) { 577 VkCommandBufferInheritanceInfo cmd_buf_hinfo = { 578 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 579 .pNext = NULL, 580 .renderPass = VK_NULL_HANDLE, 581 .subpass = 0, 582 .framebuffer = VK_NULL_HANDLE, 583 .occlusionQueryEnable = VK_FALSE, 584 .queryFlags = 0, 585 .pipelineStatistics = 0, 586 }; 587 const VkCommandBufferBeginInfo cmd_buf_info = { 588 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 589 .pNext = NULL, 590 .flags = 0, 591 .pInheritanceInfo = &cmd_buf_hinfo, 592 }; 593 const VkClearValue clear_values[2] = { 594 [0] = {.color.float32 = {0.2f, 0.2f, 0.2f, 0.2f}}, 595 [1] = {.depthStencil = {1.0f, 0}}, 596 }; 597 const VkRenderPassBeginInfo rp_begin = { 598 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 599 .pNext = NULL, 600 .renderPass = demo->render_pass, 601 .framebuffer = demo->framebuffers[demo->current_buffer], 602 .renderArea.offset.x = 0, 603 .renderArea.offset.y = 0, 604 .renderArea.extent.width = demo->width, 605 .renderArea.extent.height = demo->height, 606 .clearValueCount = 2, 607 .pClearValues = clear_values, 608 }; 609 VkResult U_ASSERT_ONLY err; 610 611 err = vkBeginCommandBuffer(cmd_buf, &cmd_buf_info); 612 assert(!err); 613 614 // We can use LAYOUT_UNDEFINED as a wildcard here because we don't care what 615 // happens to the previous contents of the image 616 VkImageMemoryBarrier image_memory_barrier = { 617 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 618 .pNext = NULL, 619 .srcAccessMask = 0, 620 .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 621 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, 622 .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 623 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 624 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 625 .image = demo->buffers[demo->current_buffer].image, 626 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; 627 628 vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 629 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, 630 NULL, 1, &image_memory_barrier); 631 632 vkCmdBeginRenderPass(cmd_buf, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); 633 634 vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline); 635 vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, 636 demo->pipeline_layout, 0, 1, &demo->desc_set, 0, 637 NULL); 638 VkViewport viewport; 639 memset(&viewport, 0, sizeof(viewport)); 640 viewport.height = (float)demo->height; 641 viewport.width = (float)demo->width; 642 viewport.minDepth = (float)0.0f; 643 viewport.maxDepth = (float)1.0f; 644 vkCmdSetViewport(cmd_buf, 0, 1, &viewport); 645 646 VkRect2D scissor; 647 memset(&scissor, 0, sizeof(scissor)); 648 scissor.extent.width = demo->width; 649 scissor.extent.height = demo->height; 650 scissor.offset.x = 0; 651 scissor.offset.y = 0; 652 vkCmdSetScissor(cmd_buf, 0, 1, &scissor); 653 vkCmdDraw(cmd_buf, 12 * 3, 1, 0, 0); 654 vkCmdEndRenderPass(cmd_buf); 655 656 VkImageMemoryBarrier prePresentBarrier = { 657 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 658 .pNext = NULL, 659 .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 660 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, 661 .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 662 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 663 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 664 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 665 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; 666 667 prePresentBarrier.image = demo->buffers[demo->current_buffer].image; 668 VkImageMemoryBarrier *pmemory_barrier = &prePresentBarrier; 669 vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 670 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, 671 NULL, 1, pmemory_barrier); 672 673 err = vkEndCommandBuffer(cmd_buf); 674 assert(!err); 675} 676 677void demo_update_data_buffer(struct demo *demo) { 678 mat4x4 MVP, Model, VP; 679 int matrixSize = sizeof(MVP); 680 uint8_t *pData; 681 VkResult U_ASSERT_ONLY err; 682 683 mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix); 684 685 // Rotate 22.5 degrees around the Y axis 686 mat4x4_dup(Model, demo->model_matrix); 687 mat4x4_rotate(demo->model_matrix, Model, 0.0f, 1.0f, 0.0f, 688 (float)degreesToRadians(demo->spin_angle)); 689 mat4x4_mul(MVP, VP, demo->model_matrix); 690 691 err = vkMapMemory(demo->device, demo->uniform_data.mem, 0, 692 demo->uniform_data.mem_alloc.allocationSize, 0, 693 (void **)&pData); 694 assert(!err); 695 696 memcpy(pData, (const void *)&MVP[0][0], matrixSize); 697 698 vkUnmapMemory(demo->device, demo->uniform_data.mem); 699} 700 701static void demo_draw(struct demo *demo) { 702 VkResult U_ASSERT_ONLY err; 703 VkSemaphore presentCompleteSemaphore; 704 VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = { 705 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 706 .pNext = NULL, 707 .flags = 0, 708 }; 709 VkFence nullFence = VK_NULL_HANDLE; 710 711 err = vkCreateSemaphore(demo->device, &presentCompleteSemaphoreCreateInfo, 712 NULL, &presentCompleteSemaphore); 713 assert(!err); 714 715 // Get the index of the next available swapchain image: 716 err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX, 717 presentCompleteSemaphore, 718 (VkFence)0, // TODO: Show use of fence 719 &demo->current_buffer); 720 if (err == VK_ERROR_OUT_OF_DATE_KHR) { 721 // demo->swapchain is out of date (e.g. the window was resized) and 722 // must be recreated: 723 demo_resize(demo); 724 demo_draw(demo); 725 vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL); 726 return; 727 } else if (err == VK_SUBOPTIMAL_KHR) { 728 // demo->swapchain is not as optimal as it could be, but the platform's 729 // presentation engine will still present the image correctly. 730 } else { 731 assert(!err); 732 } 733 734 demo_flush_init_cmd(demo); 735 736 // Wait for the present complete semaphore to be signaled to ensure 737 // that the image won't be rendered to until the presentation 738 // engine has fully released ownership to the application, and it is 739 // okay to render to the image. 740 741 VkPipelineStageFlags pipe_stage_flags = 742 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; 743 VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 744 .pNext = NULL, 745 .waitSemaphoreCount = 1, 746 .pWaitSemaphores = &presentCompleteSemaphore, 747 .pWaitDstStageMask = &pipe_stage_flags, 748 .commandBufferCount = 1, 749 .pCommandBuffers = 750 &demo->buffers[demo->current_buffer].cmd, 751 .signalSemaphoreCount = 0, 752 .pSignalSemaphores = NULL}; 753 754 err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence); 755 assert(!err); 756 757 VkPresentInfoKHR present = { 758 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 759 .pNext = NULL, 760 .swapchainCount = 1, 761 .pSwapchains = &demo->swapchain, 762 .pImageIndices = &demo->current_buffer, 763 }; 764 765 // TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER? 766 err = demo->fpQueuePresentKHR(demo->queue, &present); 767 if (err == VK_ERROR_OUT_OF_DATE_KHR) { 768 // demo->swapchain is out of date (e.g. the window was resized) and 769 // must be recreated: 770 demo_resize(demo); 771 } else if (err == VK_SUBOPTIMAL_KHR) { 772 // demo->swapchain is not as optimal as it could be, but the platform's 773 // presentation engine will still present the image correctly. 774 } else { 775 assert(!err); 776 } 777 778 err = vkQueueWaitIdle(demo->queue); 779 assert(err == VK_SUCCESS); 780 781 vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL); 782} 783 784static void demo_prepare_buffers(struct demo *demo) { 785 VkResult U_ASSERT_ONLY err; 786 VkSwapchainKHR oldSwapchain = demo->swapchain; 787 788 // Check the surface capabilities and formats 789 VkSurfaceCapabilitiesKHR surfCapabilities; 790 err = demo->fpGetPhysicalDeviceSurfaceCapabilitiesKHR( 791 demo->gpu, demo->surface, &surfCapabilities); 792 assert(!err); 793 794 uint32_t presentModeCount; 795 err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR( 796 demo->gpu, demo->surface, &presentModeCount, NULL); 797 assert(!err); 798 VkPresentModeKHR *presentModes = 799 (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR)); 800 assert(presentModes); 801 err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR( 802 demo->gpu, demo->surface, &presentModeCount, presentModes); 803 assert(!err); 804 805 VkExtent2D swapchainExtent; 806 // width and height are either both -1, or both not -1. 807 if (surfCapabilities.currentExtent.width == (uint32_t)-1) { 808 // If the surface size is undefined, the size is set to 809 // the size of the images requested. 810 swapchainExtent.width = demo->width; 811 swapchainExtent.height = demo->height; 812 } else { 813 // If the surface size is defined, the swap chain size must match 814 swapchainExtent = surfCapabilities.currentExtent; 815 demo->width = surfCapabilities.currentExtent.width; 816 demo->height = surfCapabilities.currentExtent.height; 817 } 818 819 // If mailbox mode is available, use it, as is the lowest-latency non- 820 // tearing mode. If not, try IMMEDIATE which will usually be available, 821 // and is fastest (though it tears). If not, fall back to FIFO which is 822 // always available. 823 VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; 824 for (size_t i = 0; i < presentModeCount; i++) { 825 if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { 826 swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; 827 break; 828 } 829 if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && 830 (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) { 831 swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; 832 } 833 } 834 835 // Determine the number of VkImage's to use in the swap chain (we desire to 836 // own only 1 image at a time, besides the images being displayed and 837 // queued for display): 838 uint32_t desiredNumberOfSwapchainImages = 839 surfCapabilities.minImageCount + 1; 840 if ((surfCapabilities.maxImageCount > 0) && 841 (desiredNumberOfSwapchainImages > surfCapabilities.maxImageCount)) { 842 // Application must settle for fewer images than desired: 843 desiredNumberOfSwapchainImages = surfCapabilities.maxImageCount; 844 } 845 846 VkSurfaceTransformFlagsKHR preTransform; 847 if (surfCapabilities.supportedTransforms & 848 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { 849 preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 850 } else { 851 preTransform = surfCapabilities.currentTransform; 852 } 853 854 const VkSwapchainCreateInfoKHR swapchain = { 855 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 856 .pNext = NULL, 857 .surface = demo->surface, 858 .minImageCount = desiredNumberOfSwapchainImages, 859 .imageFormat = demo->format, 860 .imageColorSpace = demo->color_space, 861 .imageExtent = 862 { 863 .width = swapchainExtent.width, .height = swapchainExtent.height, 864 }, 865 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 866 .preTransform = preTransform, 867 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, 868 .imageArrayLayers = 1, 869 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, 870 .queueFamilyIndexCount = 0, 871 .pQueueFamilyIndices = NULL, 872 .presentMode = swapchainPresentMode, 873 .oldSwapchain = oldSwapchain, 874 .clipped = true, 875 }; 876 uint32_t i; 877 878 err = demo->fpCreateSwapchainKHR(demo->device, &swapchain, NULL, 879 &demo->swapchain); 880 assert(!err); 881 882 // If we just re-created an existing swapchain, we should destroy the old 883 // swapchain at this point. 884 // Note: destroying the swapchain also cleans up all its associated 885 // presentable images once the platform is done with them. 886 if (oldSwapchain != VK_NULL_HANDLE) { 887 demo->fpDestroySwapchainKHR(demo->device, oldSwapchain, NULL); 888 } 889 890 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain, 891 &demo->swapchainImageCount, NULL); 892 assert(!err); 893 894 VkImage *swapchainImages = 895 (VkImage *)malloc(demo->swapchainImageCount * sizeof(VkImage)); 896 assert(swapchainImages); 897 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain, 898 &demo->swapchainImageCount, 899 swapchainImages); 900 assert(!err); 901 902 demo->buffers = (SwapchainBuffers *)malloc(sizeof(SwapchainBuffers) * 903 demo->swapchainImageCount); 904 assert(demo->buffers); 905 906 for (i = 0; i < demo->swapchainImageCount; i++) { 907 VkImageViewCreateInfo color_image_view = { 908 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 909 .pNext = NULL, 910 .format = demo->format, 911 .components = 912 { 913 .r = VK_COMPONENT_SWIZZLE_R, 914 .g = VK_COMPONENT_SWIZZLE_G, 915 .b = VK_COMPONENT_SWIZZLE_B, 916 .a = VK_COMPONENT_SWIZZLE_A, 917 }, 918 .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 919 .baseMipLevel = 0, 920 .levelCount = 1, 921 .baseArrayLayer = 0, 922 .layerCount = 1}, 923 .viewType = VK_IMAGE_VIEW_TYPE_2D, 924 .flags = 0, 925 }; 926 927 demo->buffers[i].image = swapchainImages[i]; 928 929 color_image_view.image = demo->buffers[i].image; 930 931 err = vkCreateImageView(demo->device, &color_image_view, NULL, 932 &demo->buffers[i].view); 933 assert(!err); 934 } 935 936 937 if (NULL != presentModes) { 938 free(presentModes); 939 } 940} 941 942static void demo_prepare_depth(struct demo *demo) { 943 const VkFormat depth_format = VK_FORMAT_D16_UNORM; 944 const VkImageCreateInfo image = { 945 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 946 .pNext = NULL, 947 .imageType = VK_IMAGE_TYPE_2D, 948 .format = depth_format, 949 .extent = {demo->width, demo->height, 1}, 950 .mipLevels = 1, 951 .arrayLayers = 1, 952 .samples = VK_SAMPLE_COUNT_1_BIT, 953 .tiling = VK_IMAGE_TILING_OPTIMAL, 954 .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 955 .flags = 0, 956 }; 957 958 VkImageViewCreateInfo view = { 959 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 960 .pNext = NULL, 961 .image = VK_NULL_HANDLE, 962 .format = depth_format, 963 .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, 964 .baseMipLevel = 0, 965 .levelCount = 1, 966 .baseArrayLayer = 0, 967 .layerCount = 1}, 968 .flags = 0, 969 .viewType = VK_IMAGE_VIEW_TYPE_2D, 970 }; 971 972 VkMemoryRequirements mem_reqs; 973 VkResult U_ASSERT_ONLY err; 974 bool U_ASSERT_ONLY pass; 975 976 demo->depth.format = depth_format; 977 978 /* create image */ 979 err = vkCreateImage(demo->device, &image, NULL, &demo->depth.image); 980 assert(!err); 981 982 vkGetImageMemoryRequirements(demo->device, demo->depth.image, &mem_reqs); 983 assert(!err); 984 985 demo->depth.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 986 demo->depth.mem_alloc.pNext = NULL; 987 demo->depth.mem_alloc.allocationSize = mem_reqs.size; 988 demo->depth.mem_alloc.memoryTypeIndex = 0; 989 990 pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, 991 0, /* No requirements */ 992 &demo->depth.mem_alloc.memoryTypeIndex); 993 assert(pass); 994 995 /* allocate memory */ 996 err = vkAllocateMemory(demo->device, &demo->depth.mem_alloc, NULL, 997 &demo->depth.mem); 998 assert(!err); 999 1000 /* bind memory */ 1001 err = 1002 vkBindImageMemory(demo->device, demo->depth.image, demo->depth.mem, 0); 1003 assert(!err); 1004 1005 demo_set_image_layout(demo, demo->depth.image, VK_IMAGE_ASPECT_DEPTH_BIT, 1006 VK_IMAGE_LAYOUT_UNDEFINED, 1007 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1008 0); 1009 1010 /* create image view */ 1011 view.image = demo->depth.image; 1012 err = vkCreateImageView(demo->device, &view, NULL, &demo->depth.view); 1013 assert(!err); 1014} 1015 1016/* Load a ppm file into memory */ 1017bool loadTexture(const char *filename, uint8_t *rgba_data, 1018 VkSubresourceLayout *layout, int32_t *width, int32_t *height) { 1019#ifdef __ANDROID__ 1020#include <lunarg.ppm.h> 1021 char *cPtr; 1022 cPtr = (char*)___lunarg_ppm; 1023 if ((unsigned char*)cPtr >= (___lunarg_ppm + ___lunarg_ppm_len) || strncmp(cPtr, "P6\n", 3)) { 1024 return false; 1025 } 1026 while(strncmp(cPtr++, "\n", 1)); 1027 sscanf(cPtr, "%u %u", height, width); 1028 if (rgba_data == NULL) { 1029 return true; 1030 } 1031 while(strncmp(cPtr++, "\n", 1)); 1032 if ((unsigned char*)cPtr >= (___lunarg_ppm + ___lunarg_ppm_len) || strncmp(cPtr, "255\n", 4)) { 1033 return false; 1034 } 1035 while(strncmp(cPtr++, "\n", 1)); 1036 1037 for (int y = 0; y < *height; y++) { 1038 uint8_t *rowPtr = rgba_data; 1039 for (int x = 0; x < *width; x++) { 1040 memcpy(rowPtr, cPtr, 3); 1041 rowPtr[3] = 255; /* Alpha of 1 */ 1042 rowPtr += 4; 1043 cPtr += 3; 1044 } 1045 rgba_data += layout->rowPitch; 1046 } 1047 1048 return true; 1049#else 1050 FILE *fPtr = fopen(filename, "rb"); 1051 char header[256], *cPtr, *tmp; 1052 1053 if (!fPtr) 1054 return false; 1055 1056 cPtr = fgets(header, 256, fPtr); // P6 1057 if (cPtr == NULL || strncmp(header, "P6\n", 3)) { 1058 fclose(fPtr); 1059 return false; 1060 } 1061 1062 do { 1063 cPtr = fgets(header, 256, fPtr); 1064 if (cPtr == NULL) { 1065 fclose(fPtr); 1066 return false; 1067 } 1068 } while (!strncmp(header, "#", 1)); 1069 1070 sscanf(header, "%u %u", height, width); 1071 if (rgba_data == NULL) { 1072 fclose(fPtr); 1073 return true; 1074 } 1075 tmp = fgets(header, 256, fPtr); // Format 1076 (void)tmp; 1077 if (cPtr == NULL || strncmp(header, "255\n", 3)) { 1078 fclose(fPtr); 1079 return false; 1080 } 1081 1082 for (int y = 0; y < *height; y++) { 1083 uint8_t *rowPtr = rgba_data; 1084 for (int x = 0; x < *width; x++) { 1085 size_t s = fread(rowPtr, 3, 1, fPtr); 1086 (void)s; 1087 rowPtr[3] = 255; /* Alpha of 1 */ 1088 rowPtr += 4; 1089 } 1090 rgba_data += layout->rowPitch; 1091 } 1092 fclose(fPtr); 1093 return true; 1094#endif 1095} 1096 1097static void demo_prepare_texture_image(struct demo *demo, const char *filename, 1098 struct texture_object *tex_obj, 1099 VkImageTiling tiling, 1100 VkImageUsageFlags usage, 1101 VkFlags required_props) { 1102 const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM; 1103 int32_t tex_width; 1104 int32_t tex_height; 1105 VkResult U_ASSERT_ONLY err; 1106 bool U_ASSERT_ONLY pass; 1107 1108 if (!loadTexture(filename, NULL, NULL, &tex_width, &tex_height)) { 1109 ERR_EXIT("Failed to load textures", "Load Texture Failure"); 1110 } 1111 1112 tex_obj->tex_width = tex_width; 1113 tex_obj->tex_height = tex_height; 1114 1115 const VkImageCreateInfo image_create_info = { 1116 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 1117 .pNext = NULL, 1118 .imageType = VK_IMAGE_TYPE_2D, 1119 .format = tex_format, 1120 .extent = {tex_width, tex_height, 1}, 1121 .mipLevels = 1, 1122 .arrayLayers = 1, 1123 .samples = VK_SAMPLE_COUNT_1_BIT, 1124 .tiling = tiling, 1125 .usage = usage, 1126 .flags = 0, 1127 .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED, 1128 }; 1129 1130 VkMemoryRequirements mem_reqs; 1131 1132 err = 1133 vkCreateImage(demo->device, &image_create_info, NULL, &tex_obj->image); 1134 assert(!err); 1135 1136 vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs); 1137 1138 tex_obj->mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 1139 tex_obj->mem_alloc.pNext = NULL; 1140 tex_obj->mem_alloc.allocationSize = mem_reqs.size; 1141 tex_obj->mem_alloc.memoryTypeIndex = 0; 1142 1143 pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, 1144 required_props, 1145 &tex_obj->mem_alloc.memoryTypeIndex); 1146 assert(pass); 1147 1148 /* allocate memory */ 1149 err = vkAllocateMemory(demo->device, &tex_obj->mem_alloc, NULL, 1150 &(tex_obj->mem)); 1151 assert(!err); 1152 1153 /* bind memory */ 1154 err = vkBindImageMemory(demo->device, tex_obj->image, tex_obj->mem, 0); 1155 assert(!err); 1156 1157 if (required_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { 1158 const VkImageSubresource subres = { 1159 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 1160 .mipLevel = 0, 1161 .arrayLayer = 0, 1162 }; 1163 VkSubresourceLayout layout; 1164 void *data; 1165 1166 vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres, 1167 &layout); 1168 1169 err = vkMapMemory(demo->device, tex_obj->mem, 0, 1170 tex_obj->mem_alloc.allocationSize, 0, &data); 1171 assert(!err); 1172 1173 if (!loadTexture(filename, data, &layout, &tex_width, &tex_height)) { 1174 fprintf(stderr, "Error loading texture: %s\n", filename); 1175 } 1176 1177 vkUnmapMemory(demo->device, tex_obj->mem); 1178 } 1179 1180 tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 1181 demo_set_image_layout(demo, tex_obj->image, VK_IMAGE_ASPECT_COLOR_BIT, 1182 VK_IMAGE_LAYOUT_PREINITIALIZED, tex_obj->imageLayout, 1183 VK_ACCESS_HOST_WRITE_BIT); 1184 /* setting the image layout does not reference the actual memory so no need 1185 * to add a mem ref */ 1186} 1187 1188static void demo_destroy_texture_image(struct demo *demo, 1189 struct texture_object *tex_objs) { 1190 /* clean up staging resources */ 1191 vkFreeMemory(demo->device, tex_objs->mem, NULL); 1192 vkDestroyImage(demo->device, tex_objs->image, NULL); 1193} 1194 1195static void demo_prepare_textures(struct demo *demo) { 1196 const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM; 1197 VkFormatProperties props; 1198 uint32_t i; 1199 1200 vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props); 1201 1202 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1203 VkResult U_ASSERT_ONLY err; 1204 1205 if ((props.linearTilingFeatures & 1206 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && 1207 !demo->use_staging_buffer) { 1208 /* Device can texture using linear textures */ 1209 demo_prepare_texture_image(demo, tex_files[i], &demo->textures[i], 1210 VK_IMAGE_TILING_LINEAR, 1211 VK_IMAGE_USAGE_SAMPLED_BIT, 1212 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); 1213 } else if (props.optimalTilingFeatures & 1214 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { 1215 /* Must use staging buffer to copy linear texture to optimized */ 1216 struct texture_object staging_texture; 1217 1218 memset(&staging_texture, 0, sizeof(staging_texture)); 1219 demo_prepare_texture_image(demo, tex_files[i], &staging_texture, 1220 VK_IMAGE_TILING_LINEAR, 1221 VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1222 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); 1223 1224 demo_prepare_texture_image( 1225 demo, tex_files[i], &demo->textures[i], VK_IMAGE_TILING_OPTIMAL, 1226 (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT), 1227 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); 1228 1229 demo_set_image_layout(demo, staging_texture.image, 1230 VK_IMAGE_ASPECT_COLOR_BIT, 1231 staging_texture.imageLayout, 1232 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1233 0); 1234 1235 demo_set_image_layout(demo, demo->textures[i].image, 1236 VK_IMAGE_ASPECT_COLOR_BIT, 1237 demo->textures[i].imageLayout, 1238 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1239 0); 1240 1241 VkImageCopy copy_region = { 1242 .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, 1243 .srcOffset = {0, 0, 0}, 1244 .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, 1245 .dstOffset = {0, 0, 0}, 1246 .extent = {staging_texture.tex_width, 1247 staging_texture.tex_height, 1}, 1248 }; 1249 vkCmdCopyImage( 1250 demo->cmd, staging_texture.image, 1251 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, demo->textures[i].image, 1252 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region); 1253 1254 demo_set_image_layout(demo, demo->textures[i].image, 1255 VK_IMAGE_ASPECT_COLOR_BIT, 1256 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1257 demo->textures[i].imageLayout, 1258 0); 1259 1260 demo_flush_init_cmd(demo); 1261 1262 demo_destroy_texture_image(demo, &staging_texture); 1263 } else { 1264 /* Can't support VK_FORMAT_R8G8B8A8_UNORM !? */ 1265 assert(!"No support for R8G8B8A8_UNORM as texture image format"); 1266 } 1267 1268 const VkSamplerCreateInfo sampler = { 1269 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 1270 .pNext = NULL, 1271 .magFilter = VK_FILTER_NEAREST, 1272 .minFilter = VK_FILTER_NEAREST, 1273 .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, 1274 .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 1275 .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 1276 .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 1277 .mipLodBias = 0.0f, 1278 .anisotropyEnable = VK_FALSE, 1279 .maxAnisotropy = 1, 1280 .compareOp = VK_COMPARE_OP_NEVER, 1281 .minLod = 0.0f, 1282 .maxLod = 0.0f, 1283 .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, 1284 .unnormalizedCoordinates = VK_FALSE, 1285 }; 1286 1287 VkImageViewCreateInfo view = { 1288 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 1289 .pNext = NULL, 1290 .image = VK_NULL_HANDLE, 1291 .viewType = VK_IMAGE_VIEW_TYPE_2D, 1292 .format = tex_format, 1293 .components = 1294 { 1295 VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, 1296 VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A, 1297 }, 1298 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}, 1299 .flags = 0, 1300 }; 1301 1302 /* create sampler */ 1303 err = vkCreateSampler(demo->device, &sampler, NULL, 1304 &demo->textures[i].sampler); 1305 assert(!err); 1306 1307 /* create image view */ 1308 view.image = demo->textures[i].image; 1309 err = vkCreateImageView(demo->device, &view, NULL, 1310 &demo->textures[i].view); 1311 assert(!err); 1312 } 1313} 1314 1315void demo_prepare_cube_data_buffer(struct demo *demo) { 1316 VkBufferCreateInfo buf_info; 1317 VkMemoryRequirements mem_reqs; 1318 uint8_t *pData; 1319 int i; 1320 mat4x4 MVP, VP; 1321 VkResult U_ASSERT_ONLY err; 1322 bool U_ASSERT_ONLY pass; 1323 struct vktexcube_vs_uniform data; 1324 1325 mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix); 1326 mat4x4_mul(MVP, VP, demo->model_matrix); 1327 memcpy(data.mvp, MVP, sizeof(MVP)); 1328 // dumpMatrix("MVP", MVP); 1329 1330 for (i = 0; i < 12 * 3; i++) { 1331 data.position[i][0] = g_vertex_buffer_data[i * 3]; 1332 data.position[i][1] = g_vertex_buffer_data[i * 3 + 1]; 1333 data.position[i][2] = g_vertex_buffer_data[i * 3 + 2]; 1334 data.position[i][3] = 1.0f; 1335 data.attr[i][0] = g_uv_buffer_data[2 * i]; 1336 data.attr[i][1] = g_uv_buffer_data[2 * i + 1]; 1337 data.attr[i][2] = 0; 1338 data.attr[i][3] = 0; 1339 } 1340 1341 memset(&buf_info, 0, sizeof(buf_info)); 1342 buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 1343 buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; 1344 buf_info.size = sizeof(data); 1345 err = 1346 vkCreateBuffer(demo->device, &buf_info, NULL, &demo->uniform_data.buf); 1347 assert(!err); 1348 1349 vkGetBufferMemoryRequirements(demo->device, demo->uniform_data.buf, 1350 &mem_reqs); 1351 1352 demo->uniform_data.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 1353 demo->uniform_data.mem_alloc.pNext = NULL; 1354 demo->uniform_data.mem_alloc.allocationSize = mem_reqs.size; 1355 demo->uniform_data.mem_alloc.memoryTypeIndex = 0; 1356 1357 pass = memory_type_from_properties( 1358 demo, mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 1359 &demo->uniform_data.mem_alloc.memoryTypeIndex); 1360 assert(pass); 1361 1362 err = vkAllocateMemory(demo->device, &demo->uniform_data.mem_alloc, NULL, 1363 &(demo->uniform_data.mem)); 1364 assert(!err); 1365 1366 err = vkMapMemory(demo->device, demo->uniform_data.mem, 0, 1367 demo->uniform_data.mem_alloc.allocationSize, 0, 1368 (void **)&pData); 1369 assert(!err); 1370 1371 memcpy(pData, &data, sizeof data); 1372 1373 vkUnmapMemory(demo->device, demo->uniform_data.mem); 1374 1375 err = vkBindBufferMemory(demo->device, demo->uniform_data.buf, 1376 demo->uniform_data.mem, 0); 1377 assert(!err); 1378 1379 demo->uniform_data.buffer_info.buffer = demo->uniform_data.buf; 1380 demo->uniform_data.buffer_info.offset = 0; 1381 demo->uniform_data.buffer_info.range = sizeof(data); 1382} 1383 1384static void demo_prepare_descriptor_layout(struct demo *demo) { 1385 const VkDescriptorSetLayoutBinding layout_bindings[2] = { 1386 [0] = 1387 { 1388 .binding = 0, 1389 .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1390 .descriptorCount = 1, 1391 .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, 1392 .pImmutableSamplers = NULL, 1393 }, 1394 [1] = 1395 { 1396 .binding = 1, 1397 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1398 .descriptorCount = DEMO_TEXTURE_COUNT, 1399 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, 1400 .pImmutableSamplers = NULL, 1401 }, 1402 }; 1403 const VkDescriptorSetLayoutCreateInfo descriptor_layout = { 1404 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 1405 .pNext = NULL, 1406 .bindingCount = 2, 1407 .pBindings = layout_bindings, 1408 }; 1409 VkResult U_ASSERT_ONLY err; 1410 1411 err = vkCreateDescriptorSetLayout(demo->device, &descriptor_layout, NULL, 1412 &demo->desc_layout); 1413 assert(!err); 1414 1415 const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = { 1416 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 1417 .pNext = NULL, 1418 .setLayoutCount = 1, 1419 .pSetLayouts = &demo->desc_layout, 1420 }; 1421 1422 err = vkCreatePipelineLayout(demo->device, &pPipelineLayoutCreateInfo, NULL, 1423 &demo->pipeline_layout); 1424 assert(!err); 1425} 1426 1427static void demo_prepare_render_pass(struct demo *demo) { 1428 const VkAttachmentDescription attachments[2] = { 1429 [0] = 1430 { 1431 .format = demo->format, 1432 .samples = VK_SAMPLE_COUNT_1_BIT, 1433 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 1434 .storeOp = VK_ATTACHMENT_STORE_OP_STORE, 1435 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 1436 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1437 .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1438 .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1439 }, 1440 [1] = 1441 { 1442 .format = demo->depth.format, 1443 .samples = VK_SAMPLE_COUNT_1_BIT, 1444 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, 1445 .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1446 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, 1447 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 1448 .initialLayout = 1449 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1450 .finalLayout = 1451 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1452 }, 1453 }; 1454 const VkAttachmentReference color_reference = { 1455 .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1456 }; 1457 const VkAttachmentReference depth_reference = { 1458 .attachment = 1, 1459 .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 1460 }; 1461 const VkSubpassDescription subpass = { 1462 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, 1463 .flags = 0, 1464 .inputAttachmentCount = 0, 1465 .pInputAttachments = NULL, 1466 .colorAttachmentCount = 1, 1467 .pColorAttachments = &color_reference, 1468 .pResolveAttachments = NULL, 1469 .pDepthStencilAttachment = &depth_reference, 1470 .preserveAttachmentCount = 0, 1471 .pPreserveAttachments = NULL, 1472 }; 1473 const VkRenderPassCreateInfo rp_info = { 1474 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 1475 .pNext = NULL, 1476 .attachmentCount = 2, 1477 .pAttachments = attachments, 1478 .subpassCount = 1, 1479 .pSubpasses = &subpass, 1480 .dependencyCount = 0, 1481 .pDependencies = NULL, 1482 }; 1483 VkResult U_ASSERT_ONLY err; 1484 1485 err = vkCreateRenderPass(demo->device, &rp_info, NULL, &demo->render_pass); 1486 assert(!err); 1487} 1488 1489//TODO: Merge shader reading 1490#ifndef __ANDROID__ 1491static VkShaderModule 1492demo_prepare_shader_module(struct demo *demo, const void *code, size_t size) { 1493 VkShaderModule module; 1494 VkShaderModuleCreateInfo moduleCreateInfo; 1495 VkResult U_ASSERT_ONLY err; 1496 1497 moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 1498 moduleCreateInfo.pNext = NULL; 1499 1500 moduleCreateInfo.codeSize = size; 1501 moduleCreateInfo.pCode = code; 1502 moduleCreateInfo.flags = 0; 1503 err = vkCreateShaderModule(demo->device, &moduleCreateInfo, NULL, &module); 1504 assert(!err); 1505 1506 return module; 1507} 1508 1509char *demo_read_spv(const char *filename, size_t *psize) { 1510 long int size; 1511 size_t U_ASSERT_ONLY retval; 1512 void *shader_code; 1513 1514 FILE *fp = fopen(filename, "rb"); 1515 if (!fp) 1516 return NULL; 1517 1518 fseek(fp, 0L, SEEK_END); 1519 size = ftell(fp); 1520 1521 fseek(fp, 0L, SEEK_SET); 1522 1523 shader_code = malloc(size); 1524 retval = fread(shader_code, size, 1, fp); 1525 assert(retval == 1); 1526 1527 *psize = size; 1528 1529 fclose(fp); 1530 return shader_code; 1531} 1532#endif 1533 1534static VkShaderModule demo_prepare_vs(struct demo *demo) { 1535#ifdef __ANDROID__ 1536 VkShaderModuleCreateInfo sh_info = {}; 1537 sh_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 1538 1539#include "cube.vert.h" 1540 sh_info.codeSize = sizeof(cube_vert); 1541 sh_info.pCode = cube_vert; 1542 VkResult U_ASSERT_ONLY err = vkCreateShaderModule(demo->device, &sh_info, NULL, &demo->vert_shader_module); 1543 assert(!err); 1544#else 1545 void *vertShaderCode; 1546 size_t size; 1547 1548 vertShaderCode = demo_read_spv("cube-vert.spv", &size); 1549 1550 demo->vert_shader_module = 1551 demo_prepare_shader_module(demo, vertShaderCode, size); 1552 1553 free(vertShaderCode); 1554#endif 1555 1556 return demo->vert_shader_module; 1557} 1558 1559static VkShaderModule demo_prepare_fs(struct demo *demo) { 1560#ifdef __ANDROID__ 1561 VkShaderModuleCreateInfo sh_info = {}; 1562 sh_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 1563 1564#include "cube.frag.h" 1565 sh_info.codeSize = sizeof(cube_frag); 1566 sh_info.pCode = cube_frag; 1567 VkResult U_ASSERT_ONLY err = vkCreateShaderModule(demo->device, &sh_info, NULL, &demo->frag_shader_module); 1568 assert(!err); 1569#else 1570 void *fragShaderCode; 1571 size_t size; 1572 1573 fragShaderCode = demo_read_spv("cube-frag.spv", &size); 1574 1575 demo->frag_shader_module = 1576 demo_prepare_shader_module(demo, fragShaderCode, size); 1577 1578 free(fragShaderCode); 1579#endif 1580 1581 return demo->frag_shader_module; 1582} 1583 1584static void demo_prepare_pipeline(struct demo *demo) { 1585 VkGraphicsPipelineCreateInfo pipeline; 1586 VkPipelineCacheCreateInfo pipelineCache; 1587 VkPipelineVertexInputStateCreateInfo vi; 1588 VkPipelineInputAssemblyStateCreateInfo ia; 1589 VkPipelineRasterizationStateCreateInfo rs; 1590 VkPipelineColorBlendStateCreateInfo cb; 1591 VkPipelineDepthStencilStateCreateInfo ds; 1592 VkPipelineViewportStateCreateInfo vp; 1593 VkPipelineMultisampleStateCreateInfo ms; 1594 VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE]; 1595 VkPipelineDynamicStateCreateInfo dynamicState; 1596 VkResult U_ASSERT_ONLY err; 1597 1598 memset(dynamicStateEnables, 0, sizeof dynamicStateEnables); 1599 memset(&dynamicState, 0, sizeof dynamicState); 1600 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; 1601 dynamicState.pDynamicStates = dynamicStateEnables; 1602 1603 memset(&pipeline, 0, sizeof(pipeline)); 1604 pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 1605 pipeline.layout = demo->pipeline_layout; 1606 1607 memset(&vi, 0, sizeof(vi)); 1608 vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 1609 1610 memset(&ia, 0, sizeof(ia)); 1611 ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 1612 ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 1613 1614 memset(&rs, 0, sizeof(rs)); 1615 rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; 1616 rs.polygonMode = VK_POLYGON_MODE_FILL; 1617 rs.cullMode = VK_CULL_MODE_BACK_BIT; 1618 rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; 1619 rs.depthClampEnable = VK_FALSE; 1620 rs.rasterizerDiscardEnable = VK_FALSE; 1621 rs.depthBiasEnable = VK_FALSE; 1622 rs.lineWidth = 1.0f; 1623 1624 memset(&cb, 0, sizeof(cb)); 1625 cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 1626 VkPipelineColorBlendAttachmentState att_state[1]; 1627 memset(att_state, 0, sizeof(att_state)); 1628 att_state[0].colorWriteMask = 0xf; 1629 att_state[0].blendEnable = VK_FALSE; 1630 cb.attachmentCount = 1; 1631 cb.pAttachments = att_state; 1632 1633 memset(&vp, 0, sizeof(vp)); 1634 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 1635 vp.viewportCount = 1; 1636 dynamicStateEnables[dynamicState.dynamicStateCount++] = 1637 VK_DYNAMIC_STATE_VIEWPORT; 1638 vp.scissorCount = 1; 1639 dynamicStateEnables[dynamicState.dynamicStateCount++] = 1640 VK_DYNAMIC_STATE_SCISSOR; 1641 1642 memset(&ds, 0, sizeof(ds)); 1643 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; 1644 ds.depthTestEnable = VK_TRUE; 1645 ds.depthWriteEnable = VK_TRUE; 1646 ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; 1647 ds.depthBoundsTestEnable = VK_FALSE; 1648 ds.back.failOp = VK_STENCIL_OP_KEEP; 1649 ds.back.passOp = VK_STENCIL_OP_KEEP; 1650 ds.back.compareOp = VK_COMPARE_OP_ALWAYS; 1651 ds.stencilTestEnable = VK_FALSE; 1652 ds.front = ds.back; 1653 1654 memset(&ms, 0, sizeof(ms)); 1655 ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 1656 ms.pSampleMask = NULL; 1657 ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; 1658 1659 // Two stages: vs and fs 1660 pipeline.stageCount = 2; 1661 VkPipelineShaderStageCreateInfo shaderStages[2]; 1662 memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo)); 1663 1664 shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1665 shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; 1666 shaderStages[0].module = demo_prepare_vs(demo); 1667 shaderStages[0].pName = "main"; 1668 1669 shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1670 shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; 1671 shaderStages[1].module = demo_prepare_fs(demo); 1672 shaderStages[1].pName = "main"; 1673 1674 memset(&pipelineCache, 0, sizeof(pipelineCache)); 1675 pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; 1676 1677 err = vkCreatePipelineCache(demo->device, &pipelineCache, NULL, 1678 &demo->pipelineCache); 1679 assert(!err); 1680 1681 pipeline.pVertexInputState = &vi; 1682 pipeline.pInputAssemblyState = &ia; 1683 pipeline.pRasterizationState = &rs; 1684 pipeline.pColorBlendState = &cb; 1685 pipeline.pMultisampleState = &ms; 1686 pipeline.pViewportState = &vp; 1687 pipeline.pDepthStencilState = &ds; 1688 pipeline.pStages = shaderStages; 1689 pipeline.renderPass = demo->render_pass; 1690 pipeline.pDynamicState = &dynamicState; 1691 1692 pipeline.renderPass = demo->render_pass; 1693 1694 err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1, 1695 &pipeline, NULL, &demo->pipeline); 1696 assert(!err); 1697 1698 vkDestroyShaderModule(demo->device, demo->frag_shader_module, NULL); 1699 vkDestroyShaderModule(demo->device, demo->vert_shader_module, NULL); 1700} 1701 1702static void demo_prepare_descriptor_pool(struct demo *demo) { 1703 const VkDescriptorPoolSize type_counts[2] = { 1704 [0] = 1705 { 1706 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1707 .descriptorCount = 1, 1708 }, 1709 [1] = 1710 { 1711 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1712 .descriptorCount = DEMO_TEXTURE_COUNT, 1713 }, 1714 }; 1715 const VkDescriptorPoolCreateInfo descriptor_pool = { 1716 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 1717 .pNext = NULL, 1718 .maxSets = 1, 1719 .poolSizeCount = 2, 1720 .pPoolSizes = type_counts, 1721 }; 1722 VkResult U_ASSERT_ONLY err; 1723 1724 err = vkCreateDescriptorPool(demo->device, &descriptor_pool, NULL, 1725 &demo->desc_pool); 1726 assert(!err); 1727} 1728 1729static void demo_prepare_descriptor_set(struct demo *demo) { 1730 VkDescriptorImageInfo tex_descs[DEMO_TEXTURE_COUNT]; 1731 VkWriteDescriptorSet writes[2]; 1732 VkResult U_ASSERT_ONLY err; 1733 uint32_t i; 1734 1735 VkDescriptorSetAllocateInfo alloc_info = { 1736 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 1737 .pNext = NULL, 1738 .descriptorPool = demo->desc_pool, 1739 .descriptorSetCount = 1, 1740 .pSetLayouts = &demo->desc_layout}; 1741 err = vkAllocateDescriptorSets(demo->device, &alloc_info, &demo->desc_set); 1742 assert(!err); 1743 1744 memset(&tex_descs, 0, sizeof(tex_descs)); 1745 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1746 tex_descs[i].sampler = demo->textures[i].sampler; 1747 tex_descs[i].imageView = demo->textures[i].view; 1748 tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 1749 } 1750 1751 memset(&writes, 0, sizeof(writes)); 1752 1753 writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 1754 writes[0].dstSet = demo->desc_set; 1755 writes[0].descriptorCount = 1; 1756 writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 1757 writes[0].pBufferInfo = &demo->uniform_data.buffer_info; 1758 1759 writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 1760 writes[1].dstSet = demo->desc_set; 1761 writes[1].dstBinding = 1; 1762 writes[1].descriptorCount = DEMO_TEXTURE_COUNT; 1763 writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 1764 writes[1].pImageInfo = tex_descs; 1765 1766 vkUpdateDescriptorSets(demo->device, 2, writes, 0, NULL); 1767} 1768 1769static void demo_prepare_framebuffers(struct demo *demo) { 1770 VkImageView attachments[2]; 1771 attachments[1] = demo->depth.view; 1772 1773 const VkFramebufferCreateInfo fb_info = { 1774 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 1775 .pNext = NULL, 1776 .renderPass = demo->render_pass, 1777 .attachmentCount = 2, 1778 .pAttachments = attachments, 1779 .width = demo->width, 1780 .height = demo->height, 1781 .layers = 1, 1782 }; 1783 VkResult U_ASSERT_ONLY err; 1784 uint32_t i; 1785 1786 demo->framebuffers = (VkFramebuffer *)malloc(demo->swapchainImageCount * 1787 sizeof(VkFramebuffer)); 1788 assert(demo->framebuffers); 1789 1790 for (i = 0; i < demo->swapchainImageCount; i++) { 1791 attachments[0] = demo->buffers[i].view; 1792 err = vkCreateFramebuffer(demo->device, &fb_info, NULL, 1793 &demo->framebuffers[i]); 1794 assert(!err); 1795 } 1796} 1797 1798static void demo_prepare(struct demo *demo) { 1799 VkResult U_ASSERT_ONLY err; 1800 1801 const VkCommandPoolCreateInfo cmd_pool_info = { 1802 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 1803 .pNext = NULL, 1804 .queueFamilyIndex = demo->graphics_queue_node_index, 1805 .flags = 0, 1806 }; 1807 err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL, 1808 &demo->cmd_pool); 1809 assert(!err); 1810 1811 const VkCommandBufferAllocateInfo cmd = { 1812 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 1813 .pNext = NULL, 1814 .commandPool = demo->cmd_pool, 1815 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1816 .commandBufferCount = 1, 1817 }; 1818 1819 demo_prepare_buffers(demo); 1820 demo_prepare_depth(demo); 1821 demo_prepare_textures(demo); 1822 demo_prepare_cube_data_buffer(demo); 1823 1824 demo_prepare_descriptor_layout(demo); 1825 demo_prepare_render_pass(demo); 1826 demo_prepare_pipeline(demo); 1827 1828 for (uint32_t i = 0; i < demo->swapchainImageCount; i++) { 1829 err = 1830 vkAllocateCommandBuffers(demo->device, &cmd, &demo->buffers[i].cmd); 1831 assert(!err); 1832 } 1833 1834 demo_prepare_descriptor_pool(demo); 1835 demo_prepare_descriptor_set(demo); 1836 1837 demo_prepare_framebuffers(demo); 1838 1839 for (uint32_t i = 0; i < demo->swapchainImageCount; i++) { 1840 demo->current_buffer = i; 1841 demo_draw_build_cmd(demo, demo->buffers[i].cmd); 1842 } 1843 1844 /* 1845 * Prepare functions above may generate pipeline commands 1846 * that need to be flushed before beginning the render loop. 1847 */ 1848 demo_flush_init_cmd(demo); 1849 1850 demo->current_buffer = 0; 1851 demo->prepared = true; 1852} 1853 1854static void demo_cleanup(struct demo *demo) { 1855 uint32_t i; 1856 1857 demo->prepared = false; 1858 1859 for (i = 0; i < demo->swapchainImageCount; i++) { 1860 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL); 1861 } 1862 free(demo->framebuffers); 1863 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL); 1864 1865 vkDestroyPipeline(demo->device, demo->pipeline, NULL); 1866 vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL); 1867 vkDestroyRenderPass(demo->device, demo->render_pass, NULL); 1868 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL); 1869 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL); 1870 1871 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1872 vkDestroyImageView(demo->device, demo->textures[i].view, NULL); 1873 vkDestroyImage(demo->device, demo->textures[i].image, NULL); 1874 vkFreeMemory(demo->device, demo->textures[i].mem, NULL); 1875 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL); 1876 } 1877 demo->fpDestroySwapchainKHR(demo->device, demo->swapchain, NULL); 1878 1879 vkDestroyImageView(demo->device, demo->depth.view, NULL); 1880 vkDestroyImage(demo->device, demo->depth.image, NULL); 1881 vkFreeMemory(demo->device, demo->depth.mem, NULL); 1882 1883 vkDestroyBuffer(demo->device, demo->uniform_data.buf, NULL); 1884 vkFreeMemory(demo->device, demo->uniform_data.mem, NULL); 1885 1886 for (i = 0; i < demo->swapchainImageCount; i++) { 1887 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL); 1888 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, 1889 &demo->buffers[i].cmd); 1890 } 1891 free(demo->buffers); 1892 1893 free(demo->queue_props); 1894 1895 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL); 1896 vkDestroyDevice(demo->device, NULL); 1897 if (demo->validate) { 1898 demo->DestroyDebugReportCallback(demo->inst, demo->msg_callback, NULL); 1899 } 1900 vkDestroySurfaceKHR(demo->inst, demo->surface, NULL); 1901 vkDestroyInstance(demo->inst, NULL); 1902 1903#if defined(VK_USE_PLATFORM_XLIB_KHR) 1904 if (demo->use_xlib) { 1905 XDestroyWindow(demo->display, demo->xlib_window); 1906 XCloseDisplay(demo->display); 1907 } else { 1908 xcb_destroy_window(demo->connection, demo->xcb_window); 1909 xcb_disconnect(demo->connection); 1910 } 1911 free(demo->atom_wm_delete_window); 1912#elif defined(VK_USE_PLATFORM_XCB_KHR) 1913 xcb_destroy_window(demo->connection, demo->window); 1914 xcb_disconnect(demo->connection); 1915 free(demo->atom_wm_delete_window); 1916#endif 1917} 1918 1919static void demo_resize(struct demo *demo) { 1920 uint32_t i; 1921 1922 // Don't react to resize until after first initialization. 1923 if (!demo->prepared) { 1924 return; 1925 } 1926 // In order to properly resize the window, we must re-create the swapchain 1927 // AND redo the command buffers, etc. 1928 // 1929 // First, perform part of the demo_cleanup() function: 1930 demo->prepared = false; 1931 1932 for (i = 0; i < demo->swapchainImageCount; i++) { 1933 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL); 1934 } 1935 free(demo->framebuffers); 1936 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL); 1937 1938 vkDestroyPipeline(demo->device, demo->pipeline, NULL); 1939 vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL); 1940 vkDestroyRenderPass(demo->device, demo->render_pass, NULL); 1941 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL); 1942 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL); 1943 1944 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1945 vkDestroyImageView(demo->device, demo->textures[i].view, NULL); 1946 vkDestroyImage(demo->device, demo->textures[i].image, NULL); 1947 vkFreeMemory(demo->device, demo->textures[i].mem, NULL); 1948 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL); 1949 } 1950 1951 vkDestroyImageView(demo->device, demo->depth.view, NULL); 1952 vkDestroyImage(demo->device, demo->depth.image, NULL); 1953 vkFreeMemory(demo->device, demo->depth.mem, NULL); 1954 1955 vkDestroyBuffer(demo->device, demo->uniform_data.buf, NULL); 1956 vkFreeMemory(demo->device, demo->uniform_data.mem, NULL); 1957 1958 for (i = 0; i < demo->swapchainImageCount; i++) { 1959 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL); 1960 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, 1961 &demo->buffers[i].cmd); 1962 } 1963 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL); 1964 free(demo->buffers); 1965 1966 // Second, re-perform the demo_prepare() function, which will re-create the 1967 // swapchain: 1968 demo_prepare(demo); 1969} 1970 1971// On MS-Windows, make this a global, so it's available to WndProc() 1972struct demo demo; 1973 1974#if defined(VK_USE_PLATFORM_WIN32_KHR) 1975static void demo_run(struct demo *demo) { 1976 if (!demo->prepared) 1977 return; 1978 // Wait for work to finish before updating MVP. 1979 vkDeviceWaitIdle(demo->device); 1980 demo_update_data_buffer(demo); 1981 1982 demo_draw(demo); 1983 1984 // Wait for work to finish before updating MVP. 1985 vkDeviceWaitIdle(demo->device); 1986 1987 demo->curFrame++; 1988 if (demo->frameCount != INT_MAX && demo->curFrame == demo->frameCount) { 1989 PostQuitMessage(validation_error); 1990 } 1991} 1992 1993// MS-Windows event handling function: 1994LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 1995 switch (uMsg) { 1996 case WM_CLOSE: 1997 PostQuitMessage(validation_error); 1998 break; 1999 case WM_PAINT: 2000 demo_run(&demo); 2001 break; 2002 case WM_SIZE: 2003 // Resize the application to the new window size, except when 2004 // it was minimized. Vulkan doesn't support images or swapchains 2005 // with width=0 and height=0. 2006 if (wParam != SIZE_MINIMIZED) { 2007 demo.width = lParam & 0xffff; 2008 demo.height = lParam & 0xffff0000 >> 16; 2009 demo_resize(&demo); 2010 } 2011 break; 2012 default: 2013 break; 2014 } 2015 return (DefWindowProc(hWnd, uMsg, wParam, lParam)); 2016} 2017 2018static void demo_create_window(struct demo *demo) { 2019 WNDCLASSEX win_class; 2020 2021 // Initialize the window class structure: 2022 win_class.cbSize = sizeof(WNDCLASSEX); 2023 win_class.style = CS_HREDRAW | CS_VREDRAW; 2024 win_class.lpfnWndProc = WndProc; 2025 win_class.cbClsExtra = 0; 2026 win_class.cbWndExtra = 0; 2027 win_class.hInstance = demo->connection; // hInstance 2028 win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); 2029 win_class.hCursor = LoadCursor(NULL, IDC_ARROW); 2030 win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 2031 win_class.lpszMenuName = NULL; 2032 win_class.lpszClassName = demo->name; 2033 win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO); 2034 // Register window class: 2035 if (!RegisterClassEx(&win_class)) { 2036 // It didn't work, so try to give a useful error: 2037 printf("Unexpected error trying to start the application!\n"); 2038 fflush(stdout); 2039 exit(1); 2040 } 2041 // Create window with the registered class: 2042 RECT wr = {0, 0, demo->width, demo->height}; 2043 AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); 2044 demo->window = CreateWindowEx(0, 2045 demo->name, // class name 2046 demo->name, // app name 2047 WS_OVERLAPPEDWINDOW | // window style 2048 WS_VISIBLE | WS_SYSMENU, 2049 100, 100, // x/y coords 2050 wr.right - wr.left, // width 2051 wr.bottom - wr.top, // height 2052 NULL, // handle to parent 2053 NULL, // handle to menu 2054 demo->connection, // hInstance 2055 NULL); // no extra parameters 2056 if (!demo->window) { 2057 // It didn't work, so try to give a useful error: 2058 printf("Cannot create a window in which to draw!\n"); 2059 fflush(stdout); 2060 exit(1); 2061 } 2062} 2063<<<<<<< 0d3f96c9766e309ab81b36fc908cdfde2ac6915a 2064#else 2065static void demo_create_xlib_window(struct demo *demo) { 2066 2067 demo->display = XOpenDisplay(NULL); 2068 long visualMask = VisualScreenMask; 2069 int numberOfVisuals; 2070 XVisualInfo vInfoTemplate; 2071 vInfoTemplate.screen = DefaultScreen(demo->display); 2072 XVisualInfo *visualInfo = XGetVisualInfo(demo->display, visualMask, 2073 &vInfoTemplate, &numberOfVisuals); 2074 2075 Colormap colormap = XCreateColormap( 2076 demo->display, RootWindow(demo->display, vInfoTemplate.screen), 2077 visualInfo->visual, AllocNone); 2078 2079 XSetWindowAttributes windowAttributes; 2080 windowAttributes.colormap = colormap; 2081 windowAttributes.background_pixel = 0xFFFFFFFF; 2082 windowAttributes.border_pixel = 0; 2083 windowAttributes.event_mask = 2084 KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask; 2085 2086 demo->xlib_window = XCreateWindow( 2087 demo->display, RootWindow(demo->display, vInfoTemplate.screen), 0, 0, 2088 demo->width, demo->height, 0, visualInfo->depth, InputOutput, 2089 visualInfo->visual, 2090 CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, &windowAttributes); 2091 2092 XSelectInput(demo->display, demo->xlib_window, ExposureMask | KeyPressMask); 2093 XMapWindow(demo->display, demo->xlib_window); 2094 XFlush(demo->display); 2095 demo->xlib_wm_delete_window = 2096 XInternAtom(demo->display, "WM_DELETE_WINDOW", False); 2097} 2098static void demo_handle_xlib_event(struct demo *demo, const XEvent *event) { 2099 switch(event->type) { 2100 case ClientMessage: 2101 if ((Atom)event->xclient.data.l[0] == demo->xlib_wm_delete_window) 2102 demo->quit = true; 2103 break; 2104 case KeyPress: 2105 switch (event->xkey.keycode) { 2106 case 0x9: // Escape 2107 demo->quit = true; 2108 break; 2109 case 0x71: // left arrow key 2110 demo->spin_angle += demo->spin_increment; 2111 break; 2112 case 0x72: // right arrow key 2113 demo->spin_angle -= demo->spin_increment; 2114 break; 2115 case 0x41: 2116 demo->pause = !demo->pause; 2117 break; 2118 } 2119 break; 2120 case ConfigureNotify: 2121 if ((demo->width != event->xconfigure.width) || 2122 (demo->height != event->xconfigure.height)) { 2123 demo->width = event->xconfigure.width; 2124 demo->height = event->xconfigure.height; 2125 demo_resize(demo); 2126 } 2127 break; 2128 default: 2129 break; 2130 } 2131 2132} 2133 2134static void demo_run_xlib(struct demo *demo) { 2135 2136 while (!demo->quit) { 2137 XEvent event; 2138 2139 if (demo->pause) { 2140 XNextEvent(demo->display, &event); 2141 demo_handle_xlib_event(demo, &event); 2142 } else { 2143 while (XPending(demo->display) > 0) { 2144 XNextEvent(demo->display, &event); 2145 demo_handle_xlib_event(demo, &event); 2146 } 2147 } 2148 2149 // Wait for work to finish before updating MVP. 2150 vkDeviceWaitIdle(demo->device); 2151 demo_update_data_buffer(demo); 2152 2153 demo_draw(demo); 2154 2155 // Wait for work to finish before updating MVP. 2156 vkDeviceWaitIdle(demo->device); 2157 demo->curFrame++; 2158 if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) 2159 demo->quit = true; 2160 } 2161} 2162 2163#elif defined(VK_USE_PLATFORM_XCB_KHR) 2164static void demo_handle_xcb_event(struct demo *demo, 2165 const xcb_generic_event_t *event) { 2166 uint8_t event_code = event->response_type & 0x7f; 2167 switch (event_code) { 2168 case XCB_EXPOSE: 2169 // TODO: Resize window 2170 break; 2171 case XCB_CLIENT_MESSAGE: 2172 if ((*(xcb_client_message_event_t *)event).data.data32[0] == 2173 (*demo->atom_wm_delete_window).atom) { 2174 demo->quit = true; 2175 } 2176 break; 2177 case XCB_KEY_RELEASE: { 2178 const xcb_key_release_event_t *key = 2179 (const xcb_key_release_event_t *)event; 2180 2181 switch (key->detail) { 2182 case 0x9: // Escape 2183 demo->quit = true; 2184 break; 2185 case 0x71: // left arrow key 2186 demo->spin_angle += demo->spin_increment; 2187 break; 2188 case 0x72: // right arrow key 2189 demo->spin_angle -= demo->spin_increment; 2190 break; 2191 case 0x41: 2192 demo->pause = !demo->pause; 2193 break; 2194 } 2195 } break; 2196 case XCB_CONFIGURE_NOTIFY: { 2197 const xcb_configure_notify_event_t *cfg = 2198 (const xcb_configure_notify_event_t *)event; 2199 if ((demo->width != cfg->width) || (demo->height != cfg->height)) { 2200 demo->width = cfg->width; 2201 demo->height = cfg->height; 2202 demo_resize(demo); 2203 } 2204 } break; 2205 default: 2206 break; 2207 } 2208} 2209 2210static void demo_run_xcb(struct demo *demo) { 2211 xcb_flush(demo->connection); 2212 2213 while (!demo->quit) { 2214 xcb_generic_event_t *event; 2215 2216 if (demo->pause) { 2217 event = xcb_wait_for_event(demo->connection); 2218 } else { 2219 event = xcb_poll_for_event(demo->connection); 2220 } 2221 if (event) { 2222 demo_handle_xcb_event(demo, event); 2223 free(event); 2224 } 2225 2226 // Wait for work to finish before updating MVP. 2227 vkDeviceWaitIdle(demo->device); 2228 demo_update_data_buffer(demo); 2229 2230 demo_draw(demo); 2231 2232 // Wait for work to finish before updating MVP. 2233 vkDeviceWaitIdle(demo->device); 2234 demo->curFrame++; 2235 if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) 2236 demo->quit = true; 2237 } 2238} 2239 2240static void demo_create_xcb_window(struct demo *demo) { 2241 uint32_t value_mask, value_list[32]; 2242 2243 demo->xcb_window = xcb_generate_id(demo->connection); 2244 2245 value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 2246 value_list[0] = demo->screen->black_pixel; 2247 value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE | 2248 XCB_EVENT_MASK_STRUCTURE_NOTIFY; 2249 2250 xcb_create_window(demo->connection, XCB_COPY_FROM_PARENT, demo->xcb_window, 2251 demo->screen->root, 0, 0, demo->width, demo->height, 0, 2252 XCB_WINDOW_CLASS_INPUT_OUTPUT, demo->screen->root_visual, 2253 value_mask, value_list); 2254 2255 /* Magic code that will send notification when window is destroyed */ 2256 xcb_intern_atom_cookie_t cookie = 2257 xcb_intern_atom(demo->connection, 1, 12, "WM_PROTOCOLS"); 2258 xcb_intern_atom_reply_t *reply = 2259 xcb_intern_atom_reply(demo->connection, cookie, 0); 2260 2261 xcb_intern_atom_cookie_t cookie2 = 2262 xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW"); 2263 demo->atom_wm_delete_window = 2264 xcb_intern_atom_reply(demo->connection, cookie2, 0); 2265 2266 xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, demo->xcb_window, 2267 (*reply).atom, 4, 32, 1, 2268 &(*demo->atom_wm_delete_window).atom); 2269 free(reply); 2270 2271 xcb_map_window(demo->connection, demo->xcb_window); 2272 2273 // Force the x/y coordinates to 100,100 results are identical in consecutive 2274 // runs 2275 const uint32_t coords[] = {100, 100}; 2276 xcb_configure_window(demo->connection, demo->xcb_window, 2277 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords); 2278} 2279#elif defined(VK_USE_PLATFORM_ANDROID_KHR) 2280static void demo_run(struct demo *demo) { 2281 if (!demo->prepared) 2282 return; 2283 2284 // Wait for work to finish before updating MVP. 2285 vkDeviceWaitIdle(demo->device); 2286 demo_update_data_buffer(demo); 2287 2288 demo_draw(demo); 2289 2290 // Wait for work to finish before updating MVP. 2291 vkDeviceWaitIdle(demo->device); 2292 2293 demo->curFrame++; 2294} 2295#endif 2296 2297/* 2298 * Return 1 (true) if all layer names specified in check_names 2299 * can be found in given layer properties. 2300 */ 2301static VkBool32 demo_check_layers(uint32_t check_count, char **check_names, 2302 uint32_t layer_count, 2303 VkLayerProperties *layers) { 2304 for (uint32_t i = 0; i < check_count; i++) { 2305 VkBool32 found = 0; 2306 for (uint32_t j = 0; j < layer_count; j++) { 2307 if (!strcmp(check_names[i], layers[j].layerName)) { 2308 found = 1; 2309 break; 2310 } 2311 } 2312 if (!found) { 2313 fprintf(stderr, "Cannot find layer: %s\n", check_names[i]); 2314 return 0; 2315 } 2316 } 2317 return 1; 2318} 2319 2320static void demo_init_vk(struct demo *demo) { 2321 VkResult err; 2322 uint32_t instance_extension_count = 0; 2323 uint32_t instance_layer_count = 0; 2324 uint32_t device_validation_layer_count = 0; 2325 char **instance_validation_layers = NULL; 2326 demo->enabled_extension_count = 0; 2327 demo->enabled_layer_count = 0; 2328 2329 char *instance_validation_layers_alt1[] = { 2330 "VK_LAYER_LUNARG_standard_validation" 2331 }; 2332 2333 char *instance_validation_layers_alt2[] = { 2334 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", 2335 "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker", 2336 "VK_LAYER_LUNARG_image", "VK_LAYER_LUNARG_core_validation", 2337 "VK_LAYER_LUNARG_swapchain", "VK_LAYER_GOOGLE_unique_objects" 2338 }; 2339 2340 /* Look for validation layers */ 2341 VkBool32 validation_found = 0; 2342 if (demo->validate) { 2343 2344 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL); 2345 assert(!err); 2346 2347 instance_validation_layers = instance_validation_layers_alt1; 2348 if (instance_layer_count > 0) { 2349 VkLayerProperties *instance_layers = 2350 malloc(sizeof (VkLayerProperties) * instance_layer_count); 2351 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, 2352 instance_layers); 2353 assert(!err); 2354 2355 2356 validation_found = demo_check_layers( 2357 ARRAY_SIZE(instance_validation_layers_alt1), 2358 instance_validation_layers, instance_layer_count, 2359 instance_layers); 2360 if (validation_found) { 2361 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1); 2362 demo->device_validation_layers[0] = "VK_LAYER_LUNARG_standard_validation"; 2363 device_validation_layer_count = 1; 2364 } else { 2365 // use alternative set of validation layers 2366 instance_validation_layers = instance_validation_layers_alt2; 2367 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2); 2368 validation_found = demo_check_layers( 2369 ARRAY_SIZE(instance_validation_layers_alt2), 2370 instance_validation_layers, instance_layer_count, 2371 instance_layers); 2372 device_validation_layer_count = 2373 ARRAY_SIZE(instance_validation_layers_alt2); 2374 for (uint32_t i = 0; i < device_validation_layer_count; i++) { 2375 demo->device_validation_layers[i] = 2376 instance_validation_layers[i]; 2377 } 2378 } 2379 free(instance_layers); 2380 } 2381 2382 if (!validation_found) { 2383 ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find " 2384 "required validation layer.\n\n" 2385 "Please look at the Getting Started guide for additional " 2386 "information.\n", 2387 "vkCreateInstance Failure"); 2388 } 2389 } 2390 2391 /* Look for instance extensions */ 2392 VkBool32 surfaceExtFound = 0; 2393 VkBool32 platformSurfaceExtFound = 0; 2394 VkBool32 xlibSurfaceExtFound = 0; 2395 memset(demo->extension_names, 0, sizeof(demo->extension_names)); 2396 2397 err = vkEnumerateInstanceExtensionProperties( 2398 NULL, &instance_extension_count, NULL); 2399 assert(!err); 2400 2401 if (instance_extension_count > 0) { 2402 VkExtensionProperties *instance_extensions = 2403 malloc(sizeof(VkExtensionProperties) * instance_extension_count); 2404 err = vkEnumerateInstanceExtensionProperties( 2405 NULL, &instance_extension_count, instance_extensions); 2406 assert(!err); 2407 for (uint32_t i = 0; i < instance_extension_count; i++) { 2408 if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME, 2409 instance_extensions[i].extensionName)) { 2410 surfaceExtFound = 1; 2411 demo->extension_names[demo->enabled_extension_count++] = 2412 VK_KHR_SURFACE_EXTENSION_NAME; 2413 } 2414#if defined(VK_USE_PLATFORM_WIN32_KHR) 2415 if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, 2416 instance_extensions[i].extensionName)) { 2417 platformSurfaceExtFound = 1; 2418 demo->extension_names[demo->enabled_extension_count++] = 2419 VK_KHR_WIN32_SURFACE_EXTENSION_NAME; 2420 } 2421#if defined(VK_USE_PLATFORM_XLIB_KHR) 2422 if (!strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, 2423 instance_extensions[i].extensionName)) { 2424 platformSurfaceExtFound = 1; 2425 xlibSurfaceExtFound = 1; 2426 demo->extension_names[demo->enabled_extension_count++] = 2427 VK_KHR_XLIB_SURFACE_EXTENSION_NAME; 2428 } 2429#elif defined(VK_USE_PLATFORM_XCB_KHR) 2430 if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME, 2431 instance_extensions[i].extensionName)) { 2432 platformSurfaceExtFound = 1; 2433 demo->extension_names[demo->enabled_extension_count++] = 2434 VK_KHR_XCB_SURFACE_EXTENSION_NAME; 2435 } 2436#elif defined(VK_USE_PLATFORM_ANDROID_KHR) 2437 if (!strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, 2438 instance_extensions[i].extensionName)) { 2439 platformSurfaceExtFound = 1; 2440 demo->extension_names[demo->enabled_extension_count++] = 2441 VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; 2442 } 2443#endif 2444 if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, 2445 instance_extensions[i].extensionName)) { 2446 if (demo->validate) { 2447 demo->extension_names[demo->enabled_extension_count++] = 2448 VK_EXT_DEBUG_REPORT_EXTENSION_NAME; 2449 } 2450 } 2451 assert(demo->enabled_extension_count < 64); 2452 } 2453 2454 free(instance_extensions); 2455 } 2456 2457 if (!surfaceExtFound) { 2458 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find " 2459 "the " VK_KHR_SURFACE_EXTENSION_NAME 2460 " extension.\n\nDo you have a compatible " 2461 "Vulkan installable client driver (ICD) installed?\nPlease " 2462 "look at the Getting Started guide for additional " 2463 "information.\n", 2464 "vkCreateInstance Failure"); 2465 } 2466 if (!platformSurfaceExtFound) { 2467#if defined(VK_USE_PLATFORM_WIN32_KHR) 2468 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find " 2469 "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME 2470 " extension.\n\nDo you have a compatible " 2471 "Vulkan installable client driver (ICD) installed?\nPlease " 2472 "look at the Getting Started guide for additional " 2473 "information.\n", 2474 "vkCreateInstance Failure"); 2475#elif defined(VK_USE_PLATFORM_XCB_KHR) 2476 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find " 2477 "the " VK_KHR_XCB_SURFACE_EXTENSION_NAME 2478 " extension.\n\nDo you have a compatible " 2479 "Vulkan installable client driver (ICD) installed?\nPlease " 2480 "look at the Getting Started guide for additional " 2481 "information.\n", 2482 "vkCreateInstance Failure"); 2483#elif defined(VK_USE_PLATFORM_ANDROID_KHR) 2484 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find " 2485 "the " VK_KHR_ANDROID_SURFACE_EXTENSION_NAME 2486 " extension.\n\nDo you have a compatible " 2487 "Vulkan installable client driver (ICD) installed?\nPlease " 2488 "look at the Getting Started guide for additional " 2489 "information.\n", 2490 "vkCreateInstance Failure"); 2491#endif 2492 } 2493#if defined(VK_USE_PLATOFMR_XLIB_KHR) 2494 if (demo->use_xlib && !xlibSurfaceExtFound) { 2495 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find " 2496 "the " VK_KHR_XLIB_SURFACE_EXTENSION_NAME 2497 " extension.\n\nDo you have a compatible " 2498 "Vulkan installable client driver (ICD) installed?\nPlease " 2499 "look at the Getting Started guide for additional " 2500 "information.\n", 2501 "vkCreateInstance Failure"); 2502 } 2503#endif 2504 const VkApplicationInfo app = { 2505 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 2506 .pNext = NULL, 2507 .pApplicationName = APP_SHORT_NAME, 2508 .applicationVersion = 0, 2509 .pEngineName = APP_SHORT_NAME, 2510 .engineVersion = 0, 2511 .apiVersion = VK_API_VERSION_1_0, 2512 }; 2513 VkInstanceCreateInfo inst_info = { 2514 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 2515 .pNext = NULL, 2516 .pApplicationInfo = &app, 2517 .enabledLayerCount = demo->enabled_layer_count, 2518 .ppEnabledLayerNames = (const char *const *)instance_validation_layers, 2519 .enabledExtensionCount = demo->enabled_extension_count, 2520 .ppEnabledExtensionNames = (const char *const *)demo->extension_names, 2521 }; 2522 2523 /* 2524 * This is info for a temp callback to use during CreateInstance. 2525 * After the instance is created, we use the instance-based 2526 * function to register the final callback. 2527 */ 2528 VkDebugReportCallbackCreateInfoEXT dbgCreateInfo; 2529 if (demo->validate) { 2530 dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; 2531 dbgCreateInfo.pNext = NULL; 2532 dbgCreateInfo.pfnCallback = demo->use_break ? BreakCallback : dbgFunc; 2533 dbgCreateInfo.pUserData = NULL; 2534 dbgCreateInfo.flags = 2535 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; 2536 inst_info.pNext = &dbgCreateInfo; 2537 } 2538 2539 uint32_t gpu_count; 2540 2541 err = vkCreateInstance(&inst_info, NULL, &demo->inst); 2542 if (err == VK_ERROR_INCOMPATIBLE_DRIVER) { 2543 ERR_EXIT("Cannot find a compatible Vulkan installable client driver " 2544 "(ICD).\n\nPlease look at the Getting Started guide for " 2545 "additional information.\n", 2546 "vkCreateInstance Failure"); 2547 } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) { 2548 ERR_EXIT("Cannot find a specified extension library" 2549 ".\nMake sure your layers path is set appropriately.\n", 2550 "vkCreateInstance Failure"); 2551 } else if (err) { 2552 ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan " 2553 "installable client driver (ICD) installed?\nPlease look at " 2554 "the Getting Started guide for additional information.\n", 2555 "vkCreateInstance Failure"); 2556 } 2557 2558 /* Make initial call to query gpu_count, then second call for gpu info*/ 2559 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL); 2560 assert(!err && gpu_count > 0); 2561 2562 if (gpu_count > 0) { 2563 VkPhysicalDevice *physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count); 2564 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, physical_devices); 2565 assert(!err); 2566 /* For cube demo we just grab the first physical device */ 2567 demo->gpu = physical_devices[0]; 2568 free(physical_devices); 2569 } else { 2570 ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible devices.\n\n" 2571 "Do you have a compatible Vulkan installable client driver (ICD) " 2572 "installed?\nPlease look at the Getting Started guide for " 2573 "additional information.\n", 2574 "vkEnumeratePhysicalDevices Failure"); 2575 } 2576 2577 /* Look for validation layers */ 2578 validation_found = 0; 2579 demo->enabled_layer_count = 0; 2580 uint32_t device_layer_count = 0; 2581 err = 2582 vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, NULL); 2583 assert(!err); 2584 2585 if (device_layer_count > 0) { 2586 VkLayerProperties *device_layers = 2587 malloc(sizeof(VkLayerProperties) * device_layer_count); 2588 err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, 2589 device_layers); 2590 assert(!err); 2591 2592 if (demo->validate) { 2593 validation_found = demo_check_layers(device_validation_layer_count, 2594 demo->device_validation_layers, 2595 device_layer_count, 2596 device_layers); 2597 demo->enabled_layer_count = device_validation_layer_count; 2598 } 2599 2600 free(device_layers); 2601 } 2602 2603 if (demo->validate && !validation_found) { 2604 ERR_EXIT("vkEnumerateDeviceLayerProperties failed to find " 2605 "a required validation layer.\n\n" 2606 "Please look at the Getting Started guide for additional " 2607 "information.\n", 2608 "vkCreateDevice Failure"); 2609 } 2610 2611 /* Look for device extensions */ 2612 uint32_t device_extension_count = 0; 2613 VkBool32 swapchainExtFound = 0; 2614 demo->enabled_extension_count = 0; 2615 memset(demo->extension_names, 0, sizeof(demo->extension_names)); 2616 2617 err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL, 2618 &device_extension_count, NULL); 2619 assert(!err); 2620 2621 if (device_extension_count > 0) { 2622 VkExtensionProperties *device_extensions = 2623 malloc(sizeof(VkExtensionProperties) * device_extension_count); 2624 err = vkEnumerateDeviceExtensionProperties( 2625 demo->gpu, NULL, &device_extension_count, device_extensions); 2626 assert(!err); 2627 2628 for (uint32_t i = 0; i < device_extension_count; i++) { 2629 if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 2630 device_extensions[i].extensionName)) { 2631 swapchainExtFound = 1; 2632 demo->extension_names[demo->enabled_extension_count++] = 2633 VK_KHR_SWAPCHAIN_EXTENSION_NAME; 2634 } 2635 assert(demo->enabled_extension_count < 64); 2636 } 2637 2638 free(device_extensions); 2639 } 2640 2641 if (!swapchainExtFound) { 2642 ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find " 2643 "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME 2644 " extension.\n\nDo you have a compatible " 2645 "Vulkan installable client driver (ICD) installed?\nPlease " 2646 "look at the Getting Started guide for additional " 2647 "information.\n", 2648 "vkCreateInstance Failure"); 2649 } 2650 2651 if (demo->validate) { 2652 demo->CreateDebugReportCallback = 2653 (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr( 2654 demo->inst, "vkCreateDebugReportCallbackEXT"); 2655 demo->DestroyDebugReportCallback = 2656 (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr( 2657 demo->inst, "vkDestroyDebugReportCallbackEXT"); 2658 if (!demo->CreateDebugReportCallback) { 2659 ERR_EXIT( 2660 "GetProcAddr: Unable to find vkCreateDebugReportCallbackEXT\n", 2661 "vkGetProcAddr Failure"); 2662 } 2663 if (!demo->DestroyDebugReportCallback) { 2664 ERR_EXIT( 2665 "GetProcAddr: Unable to find vkDestroyDebugReportCallbackEXT\n", 2666 "vkGetProcAddr Failure"); 2667 } 2668 demo->DebugReportMessage = 2669 (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr( 2670 demo->inst, "vkDebugReportMessageEXT"); 2671 if (!demo->DebugReportMessage) { 2672 ERR_EXIT("GetProcAddr: Unable to find vkDebugReportMessageEXT\n", 2673 "vkGetProcAddr Failure"); 2674 } 2675 2676 VkDebugReportCallbackCreateInfoEXT dbgCreateInfo; 2677 PFN_vkDebugReportCallbackEXT callback; 2678 callback = demo->use_break ? BreakCallback : dbgFunc; 2679 dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; 2680 dbgCreateInfo.pNext = NULL; 2681 dbgCreateInfo.pfnCallback = callback; 2682 dbgCreateInfo.pUserData = NULL; 2683 dbgCreateInfo.flags = 2684 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; 2685 err = demo->CreateDebugReportCallback(demo->inst, &dbgCreateInfo, NULL, 2686 &demo->msg_callback); 2687 switch (err) { 2688 case VK_SUCCESS: 2689 break; 2690 case VK_ERROR_OUT_OF_HOST_MEMORY: 2691 ERR_EXIT("CreateDebugReportCallback: out of host memory\n", 2692 "CreateDebugReportCallback Failure"); 2693 break; 2694 default: 2695 ERR_EXIT("CreateDebugReportCallback: unknown failure\n", 2696 "CreateDebugReportCallback Failure"); 2697 break; 2698 } 2699 } 2700 vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props); 2701 2702 /* Call with NULL data to get count */ 2703 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, 2704 NULL); 2705 assert(demo->queue_count >= 1); 2706 2707 demo->queue_props = (VkQueueFamilyProperties *)malloc( 2708 demo->queue_count * sizeof(VkQueueFamilyProperties)); 2709 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, 2710 demo->queue_props); 2711 // Find a queue that supports gfx 2712 uint32_t gfx_queue_idx = 0; 2713 for (gfx_queue_idx = 0; gfx_queue_idx < demo->queue_count; 2714 gfx_queue_idx++) { 2715 if (demo->queue_props[gfx_queue_idx].queueFlags & VK_QUEUE_GRAPHICS_BIT) 2716 break; 2717 } 2718 assert(gfx_queue_idx < demo->queue_count); 2719 // Query fine-grained feature support for this device. 2720 // If app has specific feature requirements it should check supported 2721 // features based on this query 2722 VkPhysicalDeviceFeatures physDevFeatures; 2723 vkGetPhysicalDeviceFeatures(demo->gpu, &physDevFeatures); 2724 2725 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR); 2726 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceCapabilitiesKHR); 2727 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR); 2728 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR); 2729 GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR); 2730} 2731 2732static void demo_create_device(struct demo *demo) { 2733 VkResult U_ASSERT_ONLY err; 2734 float queue_priorities[1] = {0.0}; 2735 const VkDeviceQueueCreateInfo queue = { 2736 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 2737 .pNext = NULL, 2738 .queueFamilyIndex = demo->graphics_queue_node_index, 2739 .queueCount = 1, 2740 .pQueuePriorities = queue_priorities}; 2741 2742 VkDeviceCreateInfo device = { 2743 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 2744 .pNext = NULL, 2745 .queueCreateInfoCount = 1, 2746 .pQueueCreateInfos = &queue, 2747 .enabledLayerCount = demo->enabled_layer_count, 2748 .ppEnabledLayerNames = 2749 (const char *const *)((demo->validate) 2750 ? demo->device_validation_layers 2751 : NULL), 2752 .enabledExtensionCount = demo->enabled_extension_count, 2753 .ppEnabledExtensionNames = (const char *const *)demo->extension_names, 2754 .pEnabledFeatures = 2755 NULL, // If specific features are required, pass them in here 2756 }; 2757 2758 err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device); 2759 assert(!err); 2760} 2761 2762static void demo_init_vk_swapchain(struct demo *demo) { 2763 VkResult U_ASSERT_ONLY err; 2764 uint32_t i; 2765 2766// Create a WSI surface for the window: 2767#if defined(VK_USE_PLATFORM_WIN32_KHR) 2768 VkWin32SurfaceCreateInfoKHR createInfo; 2769 createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; 2770 createInfo.pNext = NULL; 2771 createInfo.flags = 0; 2772 createInfo.hinstance = demo->connection; 2773 createInfo.hwnd = demo->window; 2774 2775 err = 2776 vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface); 2777#elif defined(VK_USE_PLATFORM_ANDROID_KHR) 2778 VkAndroidSurfaceCreateInfoKHR createInfo; 2779 createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; 2780 createInfo.pNext = NULL; 2781 createInfo.flags = 0; 2782 createInfo.window = (ANativeWindow*)(demo->window); 2783 2784 err = vkCreateAndroidSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface); 2785#endif 2786 if (demo->use_xlib) { 2787#if defined(VK_USE_PLATFORM_XCB_KHR) 2788 VkXlibSurfaceCreateInfoKHR createInfo; 2789 createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; 2790 createInfo.pNext = NULL; 2791 createInfo.flags = 0; 2792 createInfo.dpy = demo->display; 2793 createInfo.window = demo->xlib_window; 2794 2795 err = vkCreateXlibSurfaceKHR(demo->inst, &createInfo, NULL, 2796 &demo->surface); 2797#endif 2798 } 2799 else { 2800#if defined(VK_USE_PLATOFORM_X11_KHR) 2801 VkXcbSurfaceCreateInfoKHR createInfo; 2802 createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; 2803 createInfo.pNext = NULL; 2804 createInfo.flags = 0; 2805 createInfo.connection = demo->connection; 2806 createInfo.window = demo->xcb_window; 2807 2808 err = vkCreateXcbSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface); 2809#endif 2810 } 2811 assert(!err); 2812 2813 // Iterate over each queue to learn whether it supports presenting: 2814 VkBool32 *supportsPresent = 2815 (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32)); 2816 for (i = 0; i < demo->queue_count; i++) { 2817 demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface, 2818 &supportsPresent[i]); 2819 } 2820 2821 // Search for a graphics and a present queue in the array of queue 2822 // families, try to find one that supports both 2823 uint32_t graphicsQueueNodeIndex = UINT32_MAX; 2824 uint32_t presentQueueNodeIndex = UINT32_MAX; 2825 for (i = 0; i < demo->queue_count; i++) { 2826 if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { 2827 if (graphicsQueueNodeIndex == UINT32_MAX) { 2828 graphicsQueueNodeIndex = i; 2829 } 2830 2831 if (supportsPresent[i] == VK_TRUE) { 2832 graphicsQueueNodeIndex = i; 2833 presentQueueNodeIndex = i; 2834 break; 2835 } 2836 } 2837 } 2838 if (presentQueueNodeIndex == UINT32_MAX) { 2839 // If didn't find a queue that supports both graphics and present, then 2840 // find a separate present queue. 2841 for (uint32_t i = 0; i < demo->queue_count; ++i) { 2842 if (supportsPresent[i] == VK_TRUE) { 2843 presentQueueNodeIndex = i; 2844 break; 2845 } 2846 } 2847 } 2848 free(supportsPresent); 2849 2850 // Generate error if could not find both a graphics and a present queue 2851 if (graphicsQueueNodeIndex == UINT32_MAX || 2852 presentQueueNodeIndex == UINT32_MAX) { 2853 ERR_EXIT("Could not find a graphics and a present queue\n", 2854 "Swapchain Initialization Failure"); 2855 } 2856 2857 // TODO: Add support for separate queues, including presentation, 2858 // synchronization, and appropriate tracking for QueueSubmit. 2859 // NOTE: While it is possible for an application to use a separate graphics 2860 // and a present queues, this demo program assumes it is only using 2861 // one: 2862 if (graphicsQueueNodeIndex != presentQueueNodeIndex) { 2863 ERR_EXIT("Could not find a common graphics and a present queue\n", 2864 "Swapchain Initialization Failure"); 2865 } 2866 2867 demo->graphics_queue_node_index = graphicsQueueNodeIndex; 2868 2869 demo_create_device(demo); 2870 2871 GET_DEVICE_PROC_ADDR(demo->device, CreateSwapchainKHR); 2872 GET_DEVICE_PROC_ADDR(demo->device, DestroySwapchainKHR); 2873 GET_DEVICE_PROC_ADDR(demo->device, GetSwapchainImagesKHR); 2874 GET_DEVICE_PROC_ADDR(demo->device, AcquireNextImageKHR); 2875 GET_DEVICE_PROC_ADDR(demo->device, QueuePresentKHR); 2876 2877 vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 0, 2878 &demo->queue); 2879 2880 // Get the list of VkFormat's that are supported: 2881 uint32_t formatCount; 2882 err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface, 2883 &formatCount, NULL); 2884 assert(!err); 2885 VkSurfaceFormatKHR *surfFormats = 2886 (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); 2887 err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface, 2888 &formatCount, surfFormats); 2889 assert(!err); 2890 // If the format list includes just one entry of VK_FORMAT_UNDEFINED, 2891 // the surface has no preferred format. Otherwise, at least one 2892 // supported format will be returned. 2893 if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) { 2894 demo->format = VK_FORMAT_B8G8R8A8_UNORM; 2895 } else { 2896 assert(formatCount >= 1); 2897 demo->format = surfFormats[0].format; 2898 } 2899 demo->color_space = surfFormats[0].colorSpace; 2900 2901 demo->quit = false; 2902 demo->curFrame = 0; 2903 2904 // Get Memory information and properties 2905 vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties); 2906} 2907 2908static void demo_init_connection(struct demo *demo) { 2909#if defined(VK_USE_PLATFORM_XCB_KHR) 2910 const xcb_setup_t *setup; 2911 xcb_screen_iterator_t iter; 2912 int scr; 2913 2914 demo->connection = xcb_connect(NULL, &scr); 2915 if (demo->connection == NULL) { 2916 printf("Cannot find a compatible Vulkan installable client driver " 2917 "(ICD).\nExiting ...\n"); 2918 fflush(stdout); 2919 exit(1); 2920 } 2921 2922 setup = xcb_get_setup(demo->connection); 2923 iter = xcb_setup_roots_iterator(setup); 2924 while (scr-- > 0) 2925 xcb_screen_next(&iter); 2926 2927 demo->screen = iter.data; 2928#endif 2929} 2930 2931static void demo_init(struct demo *demo, int argc, char **argv) { 2932 vec3 eye = {0.0f, 3.0f, 5.0f}; 2933 vec3 origin = {0, 0, 0}; 2934 vec3 up = {0.0f, 1.0f, 0.0}; 2935 2936 memset(demo, 0, sizeof(*demo)); 2937 demo->frameCount = INT32_MAX; 2938 2939 for (int i = 1; i < argc; i++) { 2940 if (strcmp(argv[i], "--use_staging") == 0) { 2941 demo->use_staging_buffer = true; 2942 continue; 2943 } 2944 if (strcmp(argv[i], "--break") == 0) { 2945 demo->use_break = true; 2946 continue; 2947 } 2948 if (strcmp(argv[i], "--validate") == 0) { 2949 demo->validate = true; 2950 continue; 2951 } 2952 if (strcmp(argv[i], "--xlib") == 0) { 2953 demo->use_xlib = true; 2954 continue; 2955 } 2956 if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX && 2957 i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 && 2958 demo->frameCount >= 0) { 2959 i++; 2960 continue; 2961 } 2962 2963 fprintf(stderr, "Usage:\n %s [--use_staging] [--validate] [--break] " 2964 "[--c <framecount>]\n", 2965 APP_SHORT_NAME); 2966 fflush(stderr); 2967 exit(1); 2968 } 2969 2970 if (!demo->use_xlib) 2971 demo_init_connection(demo); 2972 2973 demo_init_vk(demo); 2974 2975 demo->width = 500; 2976 demo->height = 500; 2977 2978 demo->spin_angle = 0.01f; 2979 demo->spin_increment = 0.01f; 2980 demo->pause = false; 2981 2982 mat4x4_perspective(demo->projection_matrix, (float)degreesToRadians(45.0f), 2983 1.0f, 0.1f, 100.0f); 2984 mat4x4_look_at(demo->view_matrix, eye, origin, up); 2985 mat4x4_identity(demo->model_matrix); 2986} 2987 2988#if defined(VK_USE_PLATFORM_WIN32_KHR) 2989// Include header required for parsing the command line options. 2990#include <shellapi.h> 2991 2992int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, 2993 int nCmdShow) { 2994 MSG msg; // message 2995 bool done; // flag saying when app is complete 2996 int argc; 2997 char **argv; 2998 2999 // Use the CommandLine functions to get the command line arguments. 3000 // Unfortunately, Microsoft outputs 3001 // this information as wide characters for Unicode, and we simply want the 3002 // Ascii version to be compatible 3003 // with the non-Windows side. So, we have to convert the information to 3004 // Ascii character strings. 3005 LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc); 3006 if (NULL == commandLineArgs) { 3007 argc = 0; 3008 } 3009 3010 if (argc > 0) { 3011 argv = (char **)malloc(sizeof(char *) * argc); 3012 if (argv == NULL) { 3013 argc = 0; 3014 } else { 3015 for (int iii = 0; iii < argc; iii++) { 3016 size_t wideCharLen = wcslen(commandLineArgs[iii]); 3017 size_t numConverted = 0; 3018 3019 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1)); 3020 if (argv[iii] != NULL) { 3021 wcstombs_s(&numConverted, argv[iii], wideCharLen + 1, 3022 commandLineArgs[iii], wideCharLen + 1); 3023 } 3024 } 3025 } 3026 } else { 3027 argv = NULL; 3028 } 3029 3030 demo_init(&demo, argc, argv); 3031 3032 // Free up the items we had to allocate for the command line arguments. 3033 if (argc > 0 && argv != NULL) { 3034 for (int iii = 0; iii < argc; iii++) { 3035 if (argv[iii] != NULL) { 3036 free(argv[iii]); 3037 } 3038 } 3039 free(argv); 3040 } 3041 3042 demo.connection = hInstance; 3043 strncpy(demo.name, "cube", APP_NAME_STR_LEN); 3044 demo_create_window(&demo); 3045 demo_init_vk_swapchain(&demo); 3046 3047 demo_prepare(&demo); 3048 3049 done = false; // initialize loop condition variable 3050 3051 // main message loop 3052 while (!done) { 3053 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); 3054 if (msg.message == WM_QUIT) // check for a quit message 3055 { 3056 done = true; // if found, quit app 3057 } else { 3058 /* Translate and dispatch to event queue*/ 3059 TranslateMessage(&msg); 3060 DispatchMessage(&msg); 3061 } 3062 RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT); 3063 } 3064 3065 demo_cleanup(&demo); 3066 3067 return (int)msg.wParam; 3068} 3069#elif defined(VK_USE_PLATFORM_ANDROID_KHR) 3070#include <android/log.h> 3071#include <android_native_app_glue.h> 3072static bool initialized = false; 3073static bool active = false; 3074struct demo demo; 3075 3076static int32_t processInput(struct android_app* app, AInputEvent* event) { 3077 return 0; 3078} 3079 3080static void processCommand(struct android_app* app, int32_t cmd) { 3081 switch(cmd) { 3082 case APP_CMD_INIT_WINDOW: { 3083 if (app->window) { 3084 demo_init(&demo, 0, NULL); 3085 demo.window = (void*)app->window; 3086 demo_init_vk_swapchain(&demo); 3087 demo_prepare(&demo); 3088 initialized = true; 3089 } 3090 break; 3091 } 3092 case APP_CMD_GAINED_FOCUS: { 3093 active = true; 3094 break; 3095 } 3096 case APP_CMD_LOST_FOCUS: { 3097 active = false; 3098 break; 3099 } 3100 } 3101} 3102 3103void android_main(struct android_app *app) 3104{ 3105 app_dummy(); 3106 3107 app->onAppCmd = processCommand; 3108 app->onInputEvent = processInput; 3109 3110 while(1) { 3111 int events; 3112 struct android_poll_source* source; 3113 while (ALooper_pollAll(active ? 0 : -1, NULL, &events, (void**)&source) >= 0) { 3114 if (source) { 3115 source->process(app, source); 3116 } 3117 3118 if (app->destroyRequested != 0) { 3119 demo_cleanup(&demo); 3120 return; 3121 } 3122 } 3123 if (initialized && active) { 3124 demo_run(&demo); 3125 } 3126 } 3127 3128} 3129#elif defined(VK_USE_PLATFORM_XCB_KHR) 3130int main(int argc, char **argv) { 3131 struct demo demo; 3132 3133 demo_init(&demo, argc, argv); 3134 if (demo.use_xlib) 3135 demo_create_xlib_window(&demo); 3136 else 3137 demo_create_xcb_window(&demo); 3138 3139 demo_init_vk_swapchain(&demo); 3140 3141 demo_prepare(&demo); 3142 3143 if (demo.use_xlib) 3144 demo_run_xlib(&demo); 3145 else 3146 demo_run_xcb(&demo); 3147 3148 demo_cleanup(&demo); 3149 3150 return validation_error; 3151} 3152#endif 3153