tri.c revision 0d60d274605d3061e5d8ac1cf38e4e9b5ee3ff1a
1/* 2 * Vulkan 3 * 4 * Copyright (C) 2014-2015 LunarG, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24/* 25 * Draw a textured triangle with depth testing. This is written against Intel 26 * ICD. It does not do state transition nor object memory binding like it 27 * should. It also does no error checking. 28 */ 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include <stdbool.h> 34#include <assert.h> 35 36#ifdef _WIN32 37#pragma comment(linker, "/subsystem:windows") 38#include <windows.h> 39#define APP_NAME_STR_LEN 80 40#else // _WIN32 41#include <xcb/xcb.h> 42#endif // _WIN32 43 44#include <vulkan.h> 45#include <vk_wsi_lunarg.h> 46#include "vk_debug_report_lunarg.h" 47 48#include "icd-spv.h" 49 50#define DEMO_BUFFER_COUNT 2 51#define DEMO_TEXTURE_COUNT 1 52#define VERTEX_BUFFER_BIND_ID 0 53#define APP_SHORT_NAME "tri" 54#define APP_LONG_NAME "The Vulkan Triangle Demo Program" 55 56#if defined(NDEBUG) && defined(__GNUC__) 57#define U_ASSERT_ONLY __attribute__((unused)) 58#else 59#define U_ASSERT_ONLY 60#endif 61 62#ifdef _WIN32 63#define ERR_EXIT(err_msg, err_class) \ 64 do { \ 65 MessageBox(NULL, err_msg, err_class, MB_OK); \ 66 exit(1); \ 67 } while (0) 68 69// NOTE: If the following values (copied from "loader_platform.h") change, they 70// need to change here as well: 71#define LAYER_NAMES_ENV "VK_LAYER_NAMES" 72#define LAYER_NAMES_REGISTRY_VALUE "VK_LAYER_NAMES" 73#else // _WIN32 74 75#define ERR_EXIT(err_msg, err_class) \ 76 do { \ 77 printf(err_msg); \ 78 fflush(stdout); \ 79 exit(1); \ 80 } while (0) 81#endif // _WIN32 82 83#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \ 84{ \ 85 demo->fp##entrypoint = vkGetDeviceProcAddr(dev, "vk"#entrypoint); \ 86 if (demo->fp##entrypoint == NULL) { \ 87 ERR_EXIT("vkGetDeviceProcAddr failed to find vk"#entrypoint, \ 88 "vkGetDeviceProcAddr Failure"); \ 89 } \ 90} 91 92struct texture_object { 93 VkSampler sampler; 94 95 VkImage image; 96 VkImageLayout imageLayout; 97 98 VkDeviceMemory mem; 99 VkImageView view; 100 int32_t tex_width, tex_height; 101}; 102 103void dbgFunc( 104 VkFlags msgFlags, 105 VkObjectType objType, 106 VkObject srcObject, 107 size_t location, 108 int32_t msgCode, 109 const char* pLayerPrefix, 110 const char* pMsg, 111 void* pUserData) 112{ 113 char *message = (char *) malloc(strlen(pMsg)+100); 114 115 assert (message); 116 117 if (msgFlags & VK_DBG_REPORT_ERROR_BIT) { 118 sprintf(message,"ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 119 } else if (msgFlags & VK_DBG_REPORT_WARN_BIT) { 120 sprintf(message,"WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg); 121 } else { 122 return; 123 } 124 125#ifdef _WIN32 126 MessageBox(NULL, message, "Alert", MB_OK); 127#else 128 printf("%s\n",message); 129 fflush(stdout); 130#endif 131 free(message); 132} 133 134struct demo { 135#ifdef _WIN32 136#define APP_NAME_STR_LEN 80 137 HINSTANCE connection; // hInstance - Windows Instance 138 char name[APP_NAME_STR_LEN]; // Name to put on the window/icon 139 HWND window; // hWnd - window handle 140#else // _WIN32 141 xcb_connection_t *connection; 142 xcb_screen_t *screen; 143 xcb_window_t window; 144 xcb_intern_atom_reply_t *atom_wm_delete_window; 145#endif // _WIN32 146 bool prepared; 147 bool use_staging_buffer; 148 bool use_glsl; 149 150 VkInstance inst; 151 VkPhysicalDevice gpu; 152 VkDevice device; 153 VkQueue queue; 154 VkPhysicalDeviceProperties gpu_props; 155 VkPhysicalDeviceQueueProperties *queue_props; 156 uint32_t graphics_queue_node_index; 157 158 int width, height; 159 VkFormat format; 160 161 PFN_vkCreateSwapChainWSI fpCreateSwapChainWSI; 162 PFN_vkDestroySwapChainWSI fpDestroySwapChainWSI; 163 PFN_vkGetSwapChainInfoWSI fpGetSwapChainInfoWSI; 164 PFN_vkQueuePresentWSI fpQueuePresentWSI; 165 166 VkSwapChainWSI swap_chain; 167 struct { 168 VkImage image; 169 VkDeviceMemory mem; 170 171 VkColorAttachmentView view; 172 } buffers[DEMO_BUFFER_COUNT]; 173 174 struct { 175 VkFormat format; 176 177 VkImage image; 178 VkDeviceMemory mem; 179 VkDepthStencilView view; 180 } depth; 181 182 struct texture_object textures[DEMO_TEXTURE_COUNT]; 183 184 struct { 185 VkBuffer buf; 186 VkDeviceMemory mem; 187 188 VkPipelineVertexInputStateCreateInfo vi; 189 VkVertexInputBindingDescription vi_bindings[1]; 190 VkVertexInputAttributeDescription vi_attrs[2]; 191 } vertices; 192 193 VkCmdBuffer setup_cmd; // Command Buffer for initialization commands 194 VkCmdBuffer draw_cmd; // Command Buffer for drawing commands 195 VkPipelineLayout pipeline_layout; 196 VkDescriptorSetLayout desc_layout; 197 VkPipelineCache pipelineCache; 198 VkPipeline pipeline; 199 200 VkDynamicVpState viewport; 201 VkDynamicRsState raster; 202 VkDynamicCbState color_blend; 203 VkDynamicDsState depth_stencil; 204 205 VkDescriptorPool desc_pool; 206 VkDescriptorSet desc_set; 207 208 VkPhysicalDeviceMemoryProperties memory_properties; 209 210 bool validate; 211 PFN_vkDbgCreateMsgCallback dbgCreateMsgCallback; 212 VkDbgMsgCallback msg_callback; 213 214 bool quit; 215 uint32_t current_buffer; 216}; 217 218static VkResult memory_type_from_properties(struct demo *demo, uint32_t typeBits, VkFlags properties, uint32_t *typeIndex) 219{ 220 // Search memtypes to find first index with those properties 221 for (uint32_t i = 0; i < 32; i++) { 222 if ((typeBits & 1) == 1) { 223 // Type is available, does it match user properties? 224 if ((demo->memory_properties.memoryTypes[i].propertyFlags & properties) == properties) { 225 *typeIndex = i; 226 return VK_SUCCESS; 227 } 228 } 229 typeBits >>= 1; 230 } 231 // No memory types matched, return failure 232 return VK_UNSUPPORTED; 233} 234 235static void demo_flush_init_cmd(struct demo *demo) 236{ 237 VkResult U_ASSERT_ONLY err; 238 239 if (demo->setup_cmd == VK_NULL_HANDLE) 240 return; 241 242 err = vkEndCommandBuffer(demo->setup_cmd); 243 assert(!err); 244 245 const VkCmdBuffer cmd_bufs[] = { demo->setup_cmd }; 246 247 err = vkQueueSubmit(demo->queue, 1, cmd_bufs, VK_NULL_HANDLE); 248 assert(!err); 249 250 err = vkQueueWaitIdle(demo->queue); 251 assert(!err); 252 253 vkDestroyObject(demo->device, VK_OBJECT_TYPE_COMMAND_BUFFER, demo->setup_cmd); 254 demo->setup_cmd = VK_NULL_HANDLE; 255} 256 257static void demo_set_image_layout( 258 struct demo *demo, 259 VkImage image, 260 VkImageAspect aspect, 261 VkImageLayout old_image_layout, 262 VkImageLayout new_image_layout) 263{ 264 VkResult U_ASSERT_ONLY err; 265 266 if (demo->setup_cmd == VK_NULL_HANDLE) { 267 const VkCmdBufferCreateInfo cmd = { 268 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO, 269 .pNext = NULL, 270 .queueNodeIndex = demo->graphics_queue_node_index, 271 .level = VK_CMD_BUFFER_LEVEL_PRIMARY, 272 .flags = 0, 273 }; 274 275 err = vkCreateCommandBuffer(demo->device, &cmd, &demo->setup_cmd); 276 assert(!err); 277 278 VkCmdBufferBeginInfo cmd_buf_info = { 279 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, 280 .pNext = NULL, 281 .flags = VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | 282 VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT, 283 }; 284 err = vkBeginCommandBuffer(demo->setup_cmd, &cmd_buf_info); 285 } 286 287 VkImageMemoryBarrier image_memory_barrier = { 288 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 289 .pNext = NULL, 290 .outputMask = 0, 291 .inputMask = 0, 292 .oldLayout = old_image_layout, 293 .newLayout = new_image_layout, 294 .image = image, 295 .subresourceRange = { aspect, 0, 1, 0, 0 } 296 }; 297 298 if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL) { 299 /* Make sure anything that was copying from this image has completed */ 300 image_memory_barrier.inputMask = VK_MEMORY_INPUT_TRANSFER_BIT; 301 } 302 303 if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 304 /* Make sure any Copy or CPU writes to image are flushed */ 305 image_memory_barrier.outputMask = VK_MEMORY_OUTPUT_TRANSFER_BIT | VK_MEMORY_OUTPUT_HOST_WRITE_BIT; 306 } 307 308 VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier; 309 310 VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 311 VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 312 313 vkCmdPipelineBarrier(demo->setup_cmd, src_stages, dest_stages, false, 1, (const void **)&pmemory_barrier); 314} 315 316static void demo_draw_build_cmd(struct demo *demo) 317{ 318 const VkColorAttachmentBindInfo color_attachment = { 319 .view = demo->buffers[demo->current_buffer].view, 320 .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 321 }; 322 const VkDepthStencilBindInfo depth_stencil = { 323 .view = demo->depth.view, 324 .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 325 }; 326 const VkClearColorValue clear_color = { 327 .f32 = { 0.2f, 0.2f, 0.2f, 0.2f }, 328 }; 329 const float clear_depth = 0.9f; 330 VkCmdBufferBeginInfo cmd_buf_info = { 331 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, 332 .pNext = NULL, 333 .flags = VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | 334 VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT, 335 }; 336 VkResult U_ASSERT_ONLY err; 337 VkAttachmentLoadOp load_op = VK_ATTACHMENT_LOAD_OP_CLEAR; 338 VkAttachmentStoreOp store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE; 339 const VkFramebufferCreateInfo fb_info = { 340 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 341 .pNext = NULL, 342 .colorAttachmentCount = 1, 343 .pColorAttachments = (VkColorAttachmentBindInfo*) &color_attachment, 344 .pDepthStencilAttachment = (VkDepthStencilBindInfo*) &depth_stencil, 345 .sampleCount = 1, 346 .width = demo->width, 347 .height = demo->height, 348 .layers = 1, 349 }; 350 VkRenderPassCreateInfo rp_info; 351 VkRenderPassBegin rp_begin; 352 353 rp_begin.contents = VK_RENDER_PASS_CONTENTS_INLINE; 354 355 memset(&rp_info, 0 , sizeof(rp_info)); 356 err = vkCreateFramebuffer(demo->device, &fb_info, &rp_begin.framebuffer); 357 assert(!err); 358 rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; 359 rp_info.renderArea.extent.width = demo->width; 360 rp_info.renderArea.extent.height = demo->height; 361 rp_info.colorAttachmentCount = fb_info.colorAttachmentCount; 362 rp_info.pColorFormats = &demo->format; 363 rp_info.pColorLayouts = &color_attachment.layout; 364 rp_info.pColorLoadOps = &load_op; 365 rp_info.pColorStoreOps = &store_op; 366 rp_info.pColorLoadClearValues = &clear_color; 367 rp_info.depthStencilFormat = VK_FORMAT_D16_UNORM; 368 rp_info.depthStencilLayout = depth_stencil.layout; 369 rp_info.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; 370 rp_info.depthLoadClearValue = clear_depth; 371 rp_info.depthStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 372 rp_info.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 373 rp_info.stencilLoadClearValue = 0; 374 rp_info.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 375 err = vkCreateRenderPass(demo->device, &rp_info, &(rp_begin.renderPass)); 376 assert(!err); 377 378 err = vkBeginCommandBuffer(demo->draw_cmd, &cmd_buf_info); 379 assert(!err); 380 381 vkCmdBeginRenderPass(demo->draw_cmd, &rp_begin); 382 vkCmdBindPipeline(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, 383 demo->pipeline); 384 vkCmdBindDescriptorSets(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline_layout, 385 0, 1, & demo->desc_set, 0, NULL); 386 387 vkCmdBindDynamicStateObject(demo->draw_cmd, VK_STATE_BIND_POINT_VIEWPORT, demo->viewport); 388 vkCmdBindDynamicStateObject(demo->draw_cmd, VK_STATE_BIND_POINT_RASTER, demo->raster); 389 vkCmdBindDynamicStateObject(demo->draw_cmd, VK_STATE_BIND_POINT_COLOR_BLEND, 390 demo->color_blend); 391 vkCmdBindDynamicStateObject(demo->draw_cmd, VK_STATE_BIND_POINT_DEPTH_STENCIL, 392 demo->depth_stencil); 393 394 VkDeviceSize offsets[1] = {0}; 395 vkCmdBindVertexBuffers(demo->draw_cmd, VERTEX_BUFFER_BIND_ID, 1, &demo->vertices.buf, offsets); 396 397 vkCmdBeginRenderPass(demo->draw_cmd, &rp_begin); 398 399 vkCmdDraw(demo->draw_cmd, 0, 3, 0, 1); 400 vkCmdEndRenderPass(demo->draw_cmd); 401 402 err = vkEndCommandBuffer(demo->draw_cmd); 403 assert(!err); 404 405 vkDestroyObject(demo->device, VK_OBJECT_TYPE_RENDER_PASS, rp_begin.renderPass); 406 vkDestroyObject(demo->device, VK_OBJECT_TYPE_FRAMEBUFFER, rp_begin.framebuffer); 407} 408 409static void demo_draw(struct demo *demo) 410{ 411 const VkPresentInfoWSI present = { 412 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_WSI, 413 .pNext = NULL, 414 .image = demo->buffers[demo->current_buffer].image, 415 .flipInterval = 0, 416 }; 417 VkResult U_ASSERT_ONLY err; 418 419 demo_draw_build_cmd(demo); 420 421 err = vkQueueSubmit(demo->queue, 1, &demo->draw_cmd, VK_NULL_HANDLE); 422 assert(!err); 423 424 err = demo->fpQueuePresentWSI(demo->queue, &present); 425 assert(!err); 426 427 demo->current_buffer = (demo->current_buffer + 1) % DEMO_BUFFER_COUNT; 428 429 err = vkQueueWaitIdle(demo->queue); 430 assert(err == VK_SUCCESS); 431} 432 433static void demo_prepare_buffers(struct demo *demo) 434{ 435 const VkSwapChainCreateInfoWSI swap_chain = { 436 .sType = VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI, 437 .pNext = NULL, 438 .pNativeWindowSystemHandle = demo->connection, 439 .pNativeWindowHandle = (void *) (intptr_t) demo->window, 440 .displayCount = 1, 441 .imageCount = DEMO_BUFFER_COUNT, 442 .imageFormat = demo->format, 443 .imageExtent = { 444 .width = demo->width, 445 .height = demo->height, 446 }, 447 .imageArraySize = 1, 448 .imageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 449 }; 450 VkSwapChainImageInfoWSI images[DEMO_BUFFER_COUNT]; 451 size_t images_size = sizeof(images); 452 VkResult U_ASSERT_ONLY err; 453 uint32_t i; 454 455 err = demo->fpCreateSwapChainWSI(demo->device, &swap_chain, &demo->swap_chain); 456 assert(!err); 457 458 err = demo->fpGetSwapChainInfoWSI(demo->swap_chain, 459 VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_WSI, 460 &images_size, images); 461 assert(!err && images_size == sizeof(images)); 462 463 for (i = 0; i < DEMO_BUFFER_COUNT; i++) { 464 VkColorAttachmentViewCreateInfo color_attachment_view = { 465 .sType = VK_STRUCTURE_TYPE_COLOR_ATTACHMENT_VIEW_CREATE_INFO, 466 .pNext = NULL, 467 .format = demo->format, 468 .mipLevel = 0, 469 .baseArraySlice = 0, 470 .arraySize = 1, 471 }; 472 473 demo->buffers[i].image = images[i].image; 474 demo->buffers[i].mem = images[i].memory; 475 476 demo_set_image_layout(demo, demo->buffers[i].image, 477 VK_IMAGE_ASPECT_COLOR, 478 VK_IMAGE_LAYOUT_UNDEFINED, 479 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 480 481 color_attachment_view.image = demo->buffers[i].image; 482 483 err = vkCreateColorAttachmentView(demo->device, 484 &color_attachment_view, &demo->buffers[i].view); 485 assert(!err); 486 } 487 488 demo->current_buffer = 0; 489} 490 491static void demo_prepare_depth(struct demo *demo) 492{ 493 const VkFormat depth_format = VK_FORMAT_D16_UNORM; 494 const VkImageCreateInfo image = { 495 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 496 .pNext = NULL, 497 .imageType = VK_IMAGE_TYPE_2D, 498 .format = depth_format, 499 .extent = { demo->width, demo->height, 1 }, 500 .mipLevels = 1, 501 .arraySize = 1, 502 .samples = 1, 503 .tiling = VK_IMAGE_TILING_OPTIMAL, 504 .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_BIT, 505 .flags = 0, 506 }; 507 VkMemoryAllocInfo mem_alloc = { 508 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 509 .pNext = NULL, 510 .allocationSize = 0, 511 .memoryTypeIndex = 0, 512 }; 513 VkDepthStencilViewCreateInfo view = { 514 .sType = VK_STRUCTURE_TYPE_DEPTH_STENCIL_VIEW_CREATE_INFO, 515 .pNext = NULL, 516 .image = VK_NULL_HANDLE, 517 .mipLevel = 0, 518 .baseArraySlice = 0, 519 .arraySize = 1, 520 .flags = 0, 521 }; 522 523 VkMemoryRequirements mem_reqs; 524 VkResult U_ASSERT_ONLY err; 525 526 demo->depth.format = depth_format; 527 528 /* create image */ 529 err = vkCreateImage(demo->device, &image, 530 &demo->depth.image); 531 assert(!err); 532 533 /* get memory requirements for this object */ 534 err = vkGetObjectMemoryRequirements(demo->device, 535 VK_OBJECT_TYPE_IMAGE, demo->depth.image, &mem_reqs); 536 537 /* select memory size and type */ 538 mem_alloc.allocationSize = mem_reqs.size; 539 err = memory_type_from_properties(demo, 540 mem_reqs.memoryTypeBits, 541 VK_MEMORY_PROPERTY_DEVICE_ONLY, 542 &mem_alloc.memoryTypeIndex); 543 assert(!err); 544 545 /* allocate memory */ 546 err = vkAllocMemory(demo->device, &mem_alloc, &demo->depth.mem); 547 assert(!err); 548 549 /* bind memory */ 550 err = vkBindObjectMemory(demo->device, 551 VK_OBJECT_TYPE_IMAGE, demo->depth.image, 552 demo->depth.mem, 0); 553 assert(!err); 554 555 demo_set_image_layout(demo, demo->depth.image, 556 VK_IMAGE_ASPECT_DEPTH, 557 VK_IMAGE_LAYOUT_UNDEFINED, 558 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); 559 560 /* create image view */ 561 view.image = demo->depth.image; 562 err = vkCreateDepthStencilView(demo->device, &view, 563 &demo->depth.view); 564 assert(!err); 565} 566 567static void demo_prepare_texture_image(struct demo *demo, 568 const uint32_t *tex_colors, 569 struct texture_object *tex_obj, 570 VkImageTiling tiling, 571 VkImageUsageFlags usage, 572 VkFlags mem_props) 573{ 574 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; 575 const int32_t tex_width = 2; 576 const int32_t tex_height = 2; 577 VkResult U_ASSERT_ONLY err; 578 579 tex_obj->tex_width = tex_width; 580 tex_obj->tex_height = tex_height; 581 582 const VkImageCreateInfo image_create_info = { 583 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 584 .pNext = NULL, 585 .imageType = VK_IMAGE_TYPE_2D, 586 .format = tex_format, 587 .extent = { tex_width, tex_height, 1 }, 588 .mipLevels = 1, 589 .arraySize = 1, 590 .samples = 1, 591 .tiling = tiling, 592 .usage = usage, 593 .flags = 0, 594 }; 595 VkMemoryAllocInfo mem_alloc = { 596 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 597 .pNext = NULL, 598 .allocationSize = 0, 599 .memoryTypeIndex = 0, 600 }; 601 602 VkMemoryRequirements mem_reqs; 603 604 err = vkCreateImage(demo->device, &image_create_info, 605 &tex_obj->image); 606 assert(!err); 607 608 err = vkGetObjectMemoryRequirements(demo->device, 609 VK_OBJECT_TYPE_IMAGE, tex_obj->image, &mem_reqs); 610 611 mem_alloc.allocationSize = mem_reqs.size; 612 err = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, mem_props, &mem_alloc.memoryTypeIndex); 613 assert(!err); 614 615 /* allocate memory */ 616 err = vkAllocMemory(demo->device, &mem_alloc, &tex_obj->mem); 617 assert(!err); 618 619 /* bind memory */ 620 err = vkBindObjectMemory(demo->device, 621 VK_OBJECT_TYPE_IMAGE, tex_obj->image, 622 tex_obj->mem, 0); 623 assert(!err); 624 625 if (mem_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { 626 const VkImageSubresource subres = { 627 .aspect = VK_IMAGE_ASPECT_COLOR, 628 .mipLevel = 0, 629 .arraySlice = 0, 630 }; 631 VkSubresourceLayout layout; 632 void *data; 633 int32_t x, y; 634 635 err = vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres, &layout); 636 assert(!err); 637 638 err = vkMapMemory(demo->device, tex_obj->mem, 0, 0, 0, &data); 639 assert(!err); 640 641 for (y = 0; y < tex_height; y++) { 642 uint32_t *row = (uint32_t *) ((char *) data + layout.rowPitch * y); 643 for (x = 0; x < tex_width; x++) 644 row[x] = tex_colors[(x & 1) ^ (y & 1)]; 645 } 646 647 err = vkUnmapMemory(demo->device, tex_obj->mem); 648 assert(!err); 649 } 650 651 tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 652 demo_set_image_layout(demo, tex_obj->image, 653 VK_IMAGE_ASPECT_COLOR, 654 VK_IMAGE_LAYOUT_UNDEFINED, 655 tex_obj->imageLayout); 656 /* setting the image layout does not reference the actual memory so no need to add a mem ref */ 657} 658 659static void demo_destroy_texture_image(struct demo *demo, struct texture_object *tex_obj) 660{ 661 /* clean up staging resources */ 662 vkDestroyObject(demo->device, VK_OBJECT_TYPE_IMAGE, tex_obj->image); 663 vkFreeMemory(demo->device, tex_obj->mem); 664} 665 666static void demo_prepare_textures(struct demo *demo) 667{ 668 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; 669 VkFormatProperties props; 670 const uint32_t tex_colors[DEMO_TEXTURE_COUNT][2] = { 671 { 0xffff0000, 0xff00ff00 }, 672 }; 673 VkResult U_ASSERT_ONLY err; 674 uint32_t i; 675 676 err = vkGetPhysicalDeviceFormatInfo(demo->gpu, tex_format, &props); 677 assert(!err); 678 679 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 680 if ((props.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && !demo->use_staging_buffer) { 681 /* Device can texture using linear textures */ 682 demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i], 683 VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); 684 } else if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT){ 685 /* Must use staging buffer to copy linear texture to optimized */ 686 struct texture_object staging_texture; 687 688 memset(&staging_texture, 0, sizeof(staging_texture)); 689 demo_prepare_texture_image(demo, tex_colors[i], &staging_texture, 690 VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); 691 692 demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i], 693 VK_IMAGE_TILING_OPTIMAL, 694 (VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT | VK_IMAGE_USAGE_SAMPLED_BIT), 695 VK_MEMORY_PROPERTY_DEVICE_ONLY); 696 697 demo_set_image_layout(demo, staging_texture.image, 698 VK_IMAGE_ASPECT_COLOR, 699 staging_texture.imageLayout, 700 VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL); 701 702 demo_set_image_layout(demo, demo->textures[i].image, 703 VK_IMAGE_ASPECT_COLOR, 704 demo->textures[i].imageLayout, 705 VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL); 706 707 VkImageCopy copy_region = { 708 .srcSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 }, 709 .srcOffset = { 0, 0, 0 }, 710 .destSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 }, 711 .destOffset = { 0, 0, 0 }, 712 .extent = { staging_texture.tex_width, staging_texture.tex_height, 1 }, 713 }; 714 vkCmdCopyImage(demo->setup_cmd, 715 staging_texture.image, VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, 716 demo->textures[i].image, VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, 717 1, ©_region); 718 719 demo_set_image_layout(demo, demo->textures[i].image, 720 VK_IMAGE_ASPECT_COLOR, 721 VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, 722 demo->textures[i].imageLayout); 723 724 demo_flush_init_cmd(demo); 725 726 demo_destroy_texture_image(demo, &staging_texture); 727 } else { 728 /* Can't support VK_FORMAT_B8G8R8A8_UNORM !? */ 729 assert(!"No support for B8G8R8A8_UNORM as texture image format"); 730 } 731 732 const VkSamplerCreateInfo sampler = { 733 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 734 .pNext = NULL, 735 .magFilter = VK_TEX_FILTER_NEAREST, 736 .minFilter = VK_TEX_FILTER_NEAREST, 737 .mipMode = VK_TEX_MIPMAP_MODE_BASE, 738 .addressU = VK_TEX_ADDRESS_WRAP, 739 .addressV = VK_TEX_ADDRESS_WRAP, 740 .addressW = VK_TEX_ADDRESS_WRAP, 741 .mipLodBias = 0.0f, 742 .maxAnisotropy = 1, 743 .compareOp = VK_COMPARE_OP_NEVER, 744 .minLod = 0.0f, 745 .maxLod = 0.0f, 746 .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, 747 }; 748 VkImageViewCreateInfo view = { 749 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 750 .pNext = NULL, 751 .image = VK_NULL_HANDLE, 752 .viewType = VK_IMAGE_VIEW_TYPE_2D, 753 .format = tex_format, 754 .channels = { VK_CHANNEL_SWIZZLE_R, 755 VK_CHANNEL_SWIZZLE_G, 756 VK_CHANNEL_SWIZZLE_B, 757 VK_CHANNEL_SWIZZLE_A, }, 758 .subresourceRange = { VK_IMAGE_ASPECT_COLOR, 0, 1, 0, 1 }, 759 }; 760 761 /* create sampler */ 762 err = vkCreateSampler(demo->device, &sampler, 763 &demo->textures[i].sampler); 764 assert(!err); 765 766 /* create image view */ 767 view.image = demo->textures[i].image; 768 err = vkCreateImageView(demo->device, &view, 769 &demo->textures[i].view); 770 assert(!err); 771 } 772} 773 774static void demo_prepare_vertices(struct demo *demo) 775{ 776 const float vb[3][5] = { 777 /* position texcoord */ 778 { -1.0f, -1.0f, 0.2f, 0.0f, 0.0f }, 779 { 1.0f, -1.0f, 0.25f, 1.0f, 0.0f }, 780 { 0.0f, 1.0f, 1.0f, 0.5f, 1.0f }, 781 }; 782 const VkBufferCreateInfo buf_info = { 783 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 784 .pNext = NULL, 785 .size = sizeof(vb), 786 .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 787 .flags = 0, 788 }; 789 VkMemoryAllocInfo mem_alloc = { 790 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 791 .pNext = NULL, 792 .allocationSize = 0, 793 .memoryTypeIndex = 0, 794 }; 795 VkMemoryRequirements mem_reqs; 796 VkResult U_ASSERT_ONLY err; 797 void *data; 798 799 memset(&demo->vertices, 0, sizeof(demo->vertices)); 800 801 err = vkCreateBuffer(demo->device, &buf_info, &demo->vertices.buf); 802 assert(!err); 803 804 err = vkGetObjectMemoryRequirements(demo->device, 805 VK_OBJECT_TYPE_BUFFER, demo->vertices.buf, &mem_reqs); 806 807 mem_alloc.allocationSize = mem_reqs.size; 808 err = memory_type_from_properties(demo, 809 mem_reqs.memoryTypeBits, 810 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 811 &mem_alloc.memoryTypeIndex); 812 assert(!err); 813 814 err = vkAllocMemory(demo->device, &mem_alloc, &demo->vertices.mem); 815 assert(!err); 816 817 err = vkMapMemory(demo->device, demo->vertices.mem, 0, 0, 0, &data); 818 assert(!err); 819 820 memcpy(data, vb, sizeof(vb)); 821 822 err = vkUnmapMemory(demo->device, demo->vertices.mem); 823 assert(!err); 824 825 err = vkBindObjectMemory(demo->device, 826 VK_OBJECT_TYPE_BUFFER, demo->vertices.buf, 827 demo->vertices.mem, 0); 828 assert(!err); 829 830 demo->vertices.vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 831 demo->vertices.vi.pNext = NULL; 832 demo->vertices.vi.bindingCount = 1; 833 demo->vertices.vi.pVertexBindingDescriptions = demo->vertices.vi_bindings; 834 demo->vertices.vi.attributeCount = 2; 835 demo->vertices.vi.pVertexAttributeDescriptions = demo->vertices.vi_attrs; 836 837 demo->vertices.vi_bindings[0].binding = VERTEX_BUFFER_BIND_ID; 838 demo->vertices.vi_bindings[0].strideInBytes = sizeof(vb[0]); 839 demo->vertices.vi_bindings[0].stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX; 840 841 demo->vertices.vi_attrs[0].binding = VERTEX_BUFFER_BIND_ID; 842 demo->vertices.vi_attrs[0].location = 0; 843 demo->vertices.vi_attrs[0].format = VK_FORMAT_R32G32B32_SFLOAT; 844 demo->vertices.vi_attrs[0].offsetInBytes = 0; 845 846 demo->vertices.vi_attrs[1].binding = VERTEX_BUFFER_BIND_ID; 847 demo->vertices.vi_attrs[1].location = 1; 848 demo->vertices.vi_attrs[1].format = VK_FORMAT_R32G32_SFLOAT; 849 demo->vertices.vi_attrs[1].offsetInBytes = sizeof(float) * 3; 850} 851 852static void demo_prepare_descriptor_layout(struct demo *demo) 853{ 854 const VkDescriptorSetLayoutBinding layout_binding = { 855 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 856 .arraySize = DEMO_TEXTURE_COUNT, 857 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, 858 .pImmutableSamplers = NULL, 859 }; 860 const VkDescriptorSetLayoutCreateInfo descriptor_layout = { 861 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 862 .pNext = NULL, 863 .count = 1, 864 .pBinding = &layout_binding, 865 }; 866 VkResult U_ASSERT_ONLY err; 867 868 err = vkCreateDescriptorSetLayout(demo->device, 869 &descriptor_layout, &demo->desc_layout); 870 assert(!err); 871 872 const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = { 873 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 874 .pNext = NULL, 875 .descriptorSetCount = 1, 876 .pSetLayouts = &demo->desc_layout, 877 }; 878 879 err = vkCreatePipelineLayout(demo->device, 880 &pPipelineLayoutCreateInfo, 881 &demo->pipeline_layout); 882 assert(!err); 883} 884 885static VkShader demo_prepare_shader(struct demo *demo, 886 VkShaderStage stage, 887 const void *code, 888 size_t size) 889{ 890 VkShaderModuleCreateInfo moduleCreateInfo; 891 VkShaderCreateInfo shaderCreateInfo; 892 VkShaderModule shaderModule; 893 VkShader shader; 894 VkResult err; 895 896 897 moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 898 moduleCreateInfo.pNext = NULL; 899 900 shaderCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO; 901 shaderCreateInfo.pNext = NULL; 902 903 if (!demo->use_glsl) { 904 moduleCreateInfo.codeSize = size; 905 moduleCreateInfo.pCode = code; 906 moduleCreateInfo.flags = 0; 907 err = vkCreateShaderModule(demo->device, &moduleCreateInfo, &shaderModule); 908 if (err) { 909 free((void *) moduleCreateInfo.pCode); 910 } 911 912 shaderCreateInfo.flags = 0; 913 shaderCreateInfo.module = shaderModule; 914 err = vkCreateShader(demo->device, &shaderCreateInfo, &shader); 915 } else { 916 // Create fake SPV structure to feed GLSL 917 // to the driver "under the covers" 918 moduleCreateInfo.codeSize = 3 * sizeof(uint32_t) + size + 1; 919 moduleCreateInfo.pCode = malloc(moduleCreateInfo.codeSize); 920 moduleCreateInfo.flags = 0; 921 922 /* try version 0 first: VkShaderStage followed by GLSL */ 923 ((uint32_t *) moduleCreateInfo.pCode)[0] = ICD_SPV_MAGIC; 924 ((uint32_t *) moduleCreateInfo.pCode)[1] = 0; 925 ((uint32_t *) moduleCreateInfo.pCode)[2] = stage; 926 memcpy(((uint32_t *) moduleCreateInfo.pCode + 3), code, size + 1); 927 928 err = vkCreateShaderModule(demo->device, &moduleCreateInfo, &shaderModule); 929 if (err) { 930 free((void *) moduleCreateInfo.pCode); 931 } 932 933 shaderCreateInfo.flags = 0; 934 shaderCreateInfo.module = shaderModule; 935 err = vkCreateShader(demo->device, &shaderCreateInfo, &shader); 936 } 937 return shader; 938} 939 940char *demo_read_spv(const char *filename, size_t *psize) 941{ 942 long int size; 943 void *shader_code; 944 945 FILE *fp = fopen(filename, "rb"); 946 if (!fp) return NULL; 947 948 fseek(fp, 0L, SEEK_END); 949 size = ftell(fp); 950 951 fseek(fp, 0L, SEEK_SET); 952 953 shader_code = malloc(size); 954 fread(shader_code, size, 1, fp); 955 956 *psize = size; 957 958 return shader_code; 959} 960 961static VkShader demo_prepare_vs(struct demo *demo) 962{ 963 if (!demo->use_glsl) { 964 void *vertShaderCode; 965 size_t size; 966 967 vertShaderCode = demo_read_spv("tri-vert.spv", &size); 968 969 return demo_prepare_shader(demo, VK_SHADER_STAGE_VERTEX, 970 vertShaderCode, size); 971 } else { 972 static const char *vertShaderText = 973 "#version 140\n" 974 "#extension GL_ARB_separate_shader_objects : enable\n" 975 "#extension GL_ARB_shading_language_420pack : enable\n" 976 "layout (location = 0) in vec4 pos;\n" 977 "layout (location = 1) in vec2 attr;\n" 978 "out vec2 texcoord;\n" 979 "void main() {\n" 980 " texcoord = attr;\n" 981 " gl_Position = pos;\n" 982 "}\n"; 983 984 return demo_prepare_shader(demo, VK_SHADER_STAGE_VERTEX, 985 (const void *) vertShaderText, 986 strlen(vertShaderText)); 987 } 988} 989 990static VkShader demo_prepare_fs(struct demo *demo) 991{ 992 if (!demo->use_glsl) { 993 void *fragShaderCode; 994 size_t size; 995 996 fragShaderCode = demo_read_spv("tri-frag.spv", &size); 997 998 return demo_prepare_shader(demo, VK_SHADER_STAGE_FRAGMENT, 999 fragShaderCode, size); 1000 } else { 1001 static const char *fragShaderText = 1002 "#version 140\n" 1003 "#extension GL_ARB_separate_shader_objects : enable\n" 1004 "#extension GL_ARB_shading_language_420pack : enable\n" 1005 "layout (binding = 0) uniform sampler2D tex;\n" 1006 "layout (location = 0) in vec2 texcoord;\n" 1007 "layout (location = 0) out vec4 uFragColor;\n" 1008 "void main() {\n" 1009 " uFragColor = texture(tex, texcoord);\n" 1010 "}\n"; 1011 1012 return demo_prepare_shader(demo, VK_SHADER_STAGE_FRAGMENT, 1013 (const void *) fragShaderText, 1014 strlen(fragShaderText)); 1015 } 1016} 1017 1018static void demo_prepare_pipeline(struct demo *demo) 1019{ 1020 VkGraphicsPipelineCreateInfo pipeline; 1021 VkPipelineCacheCreateInfo pipelineCache; 1022 1023 VkPipelineVertexInputStateCreateInfo vi; 1024 VkPipelineIaStateCreateInfo ia; 1025 VkPipelineRsStateCreateInfo rs; 1026 VkPipelineCbStateCreateInfo cb; 1027 VkPipelineDsStateCreateInfo ds; 1028 VkPipelineVpStateCreateInfo vp; 1029 VkPipelineMsStateCreateInfo ms; 1030 1031 VkResult U_ASSERT_ONLY err; 1032 1033 memset(&pipeline, 0, sizeof(pipeline)); 1034 pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 1035 pipeline.layout = demo->pipeline_layout; 1036 1037 vi = demo->vertices.vi; 1038 1039 memset(&ia, 0, sizeof(ia)); 1040 ia.sType = VK_STRUCTURE_TYPE_PIPELINE_IA_STATE_CREATE_INFO; 1041 ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 1042 1043 memset(&rs, 0, sizeof(rs)); 1044 rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RS_STATE_CREATE_INFO; 1045 rs.fillMode = VK_FILL_MODE_SOLID; 1046 rs.cullMode = VK_CULL_MODE_BACK; 1047 rs.frontFace = VK_FRONT_FACE_CW; 1048 rs.depthClipEnable = VK_TRUE; 1049 1050 memset(&cb, 0, sizeof(cb)); 1051 cb.sType = VK_STRUCTURE_TYPE_PIPELINE_CB_STATE_CREATE_INFO; 1052 VkPipelineCbAttachmentState att_state[1]; 1053 memset(att_state, 0, sizeof(att_state)); 1054 att_state[0].format = demo->format; 1055 att_state[0].channelWriteMask = 0xf; 1056 att_state[0].blendEnable = VK_FALSE; 1057 cb.attachmentCount = 1; 1058 cb.pAttachments = att_state; 1059 1060 memset(&vp, 0, sizeof(vp)); 1061 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VP_STATE_CREATE_INFO; 1062 vp.viewportCount = 1; 1063 vp.clipOrigin = VK_COORDINATE_ORIGIN_UPPER_LEFT; 1064 1065 memset(&ds, 0, sizeof(ds)); 1066 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DS_STATE_CREATE_INFO; 1067 ds.format = demo->depth.format; 1068 ds.depthTestEnable = VK_TRUE; 1069 ds.depthWriteEnable = VK_TRUE; 1070 ds.depthCompareOp = VK_COMPARE_OP_LESS_EQUAL; 1071 ds.depthBoundsEnable = VK_FALSE; 1072 ds.back.stencilFailOp = VK_STENCIL_OP_KEEP; 1073 ds.back.stencilPassOp = VK_STENCIL_OP_KEEP; 1074 ds.back.stencilCompareOp = VK_COMPARE_OP_ALWAYS; 1075 ds.stencilTestEnable = VK_FALSE; 1076 ds.front = ds.back; 1077 1078 memset(&ms, 0, sizeof(ms)); 1079 ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MS_STATE_CREATE_INFO; 1080 ms.sampleMask = 1; 1081 ms.multisampleEnable = VK_FALSE; 1082 ms.rasterSamples = 1; 1083 1084 // Two stages: vs and fs 1085 pipeline.stageCount = 2; 1086 VkPipelineShaderStageCreateInfo shaderStages[2]; 1087 memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo)); 1088 1089 shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1090 shaderStages[0].stage = VK_SHADER_STAGE_VERTEX; 1091 shaderStages[0].shader = demo_prepare_vs(demo); 1092 shaderStages[0].linkConstBufferCount = 0; 1093 1094 shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1095 shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT; 1096 shaderStages[1].shader = demo_prepare_fs(demo); 1097 1098 pipeline.pVertexInputState = &vi; 1099 pipeline.pIaState = &ia; 1100 pipeline.pRsState = &rs; 1101 pipeline.pCbState = &cb; 1102 pipeline.pMsState = &ms; 1103 pipeline.pVpState = &vp; 1104 pipeline.pDsState = &ds; 1105 pipeline.pStages = shaderStages; 1106 1107 memset(&pipelineCache, 0, sizeof(pipelineCache)); 1108 pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; 1109 1110 err = vkCreatePipelineCache(demo->device, &pipelineCache, &demo->pipelineCache); 1111 assert(!err); 1112 err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1, &pipeline, &demo->pipeline); 1113 assert(!err); 1114 1115 for (uint32_t i = 0; i < pipeline.stageCount; i++) { 1116 vkDestroyObject(demo->device, VK_OBJECT_TYPE_SHADER, shaderStages[i].shader); 1117 } 1118} 1119 1120static void demo_prepare_dynamic_states(struct demo *demo) 1121{ 1122 VkDynamicVpStateCreateInfo viewport_create; 1123 VkDynamicRsStateCreateInfo raster; 1124 VkDynamicCbStateCreateInfo color_blend; 1125 VkDynamicDsStateCreateInfo depth_stencil; 1126 VkResult U_ASSERT_ONLY err; 1127 1128 memset(&viewport_create, 0, sizeof(viewport_create)); 1129 viewport_create.sType = VK_STRUCTURE_TYPE_DYNAMIC_VP_STATE_CREATE_INFO; 1130 viewport_create.viewportAndScissorCount = 1; 1131 VkViewport viewport; 1132 memset(&viewport, 0, sizeof(viewport)); 1133 viewport.height = (float) demo->height; 1134 viewport.width = (float) demo->width; 1135 viewport.minDepth = (float) 0.0f; 1136 viewport.maxDepth = (float) 1.0f; 1137 viewport_create.pViewports = &viewport; 1138 VkRect2D scissor; 1139 memset(&scissor, 0, sizeof(scissor)); 1140 scissor.extent.width = demo->width; 1141 scissor.extent.height = demo->height; 1142 scissor.offset.x = 0; 1143 scissor.offset.y = 0; 1144 viewport_create.pScissors = &scissor; 1145 1146 memset(&raster, 0, sizeof(raster)); 1147 raster.sType = VK_STRUCTURE_TYPE_DYNAMIC_RS_STATE_CREATE_INFO; 1148 raster.lineWidth = 1.0; 1149 1150 memset(&color_blend, 0, sizeof(color_blend)); 1151 color_blend.sType = VK_STRUCTURE_TYPE_DYNAMIC_CB_STATE_CREATE_INFO; 1152 color_blend.blendConst[0] = 1.0f; 1153 color_blend.blendConst[1] = 1.0f; 1154 color_blend.blendConst[2] = 1.0f; 1155 color_blend.blendConst[3] = 1.0f; 1156 1157 memset(&depth_stencil, 0, sizeof(depth_stencil)); 1158 depth_stencil.sType = VK_STRUCTURE_TYPE_DYNAMIC_DS_STATE_CREATE_INFO; 1159 depth_stencil.minDepthBounds = 0.0f; 1160 depth_stencil.maxDepthBounds = 1.0f; 1161 depth_stencil.stencilBackRef = 0; 1162 depth_stencil.stencilFrontRef = 0; 1163 depth_stencil.stencilReadMask = 0xff; 1164 depth_stencil.stencilWriteMask = 0xff; 1165 1166 err = vkCreateDynamicViewportState(demo->device, &viewport_create, &demo->viewport); 1167 assert(!err); 1168 1169 err = vkCreateDynamicRasterState(demo->device, &raster, &demo->raster); 1170 assert(!err); 1171 1172 err = vkCreateDynamicColorBlendState(demo->device, 1173 &color_blend, &demo->color_blend); 1174 assert(!err); 1175 1176 err = vkCreateDynamicDepthStencilState(demo->device, 1177 &depth_stencil, &demo->depth_stencil); 1178 assert(!err); 1179} 1180 1181static void demo_prepare_descriptor_pool(struct demo *demo) 1182{ 1183 const VkDescriptorTypeCount type_count = { 1184 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1185 .count = DEMO_TEXTURE_COUNT, 1186 }; 1187 const VkDescriptorPoolCreateInfo descriptor_pool = { 1188 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 1189 .pNext = NULL, 1190 .count = 1, 1191 .pTypeCount = &type_count, 1192 }; 1193 VkResult U_ASSERT_ONLY err; 1194 1195 err = vkCreateDescriptorPool(demo->device, 1196 VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1, 1197 &descriptor_pool, &demo->desc_pool); 1198 assert(!err); 1199} 1200 1201static void demo_prepare_descriptor_set(struct demo *demo) 1202{ 1203 VkDescriptorInfo tex_descs[DEMO_TEXTURE_COUNT]; 1204 VkWriteDescriptorSet write; 1205 VkResult U_ASSERT_ONLY err; 1206 uint32_t count; 1207 uint32_t i; 1208 1209 err = vkAllocDescriptorSets(demo->device, demo->desc_pool, 1210 VK_DESCRIPTOR_SET_USAGE_STATIC, 1211 1, &demo->desc_layout, 1212 &demo->desc_set, &count); 1213 assert(!err && count == 1); 1214 1215 memset(&tex_descs, 0, sizeof(tex_descs)); 1216 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1217 tex_descs[i].sampler = demo->textures[i].sampler; 1218 tex_descs[i].imageView = demo->textures[i].view; 1219 tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 1220 } 1221 1222 memset(&write, 0, sizeof(write)); 1223 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 1224 write.destSet = demo->desc_set; 1225 write.count = DEMO_TEXTURE_COUNT; 1226 write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 1227 write.pDescriptors = tex_descs; 1228 1229 err = vkUpdateDescriptorSets(demo->device, 1, &write, 0, NULL); 1230 assert(!err); 1231} 1232 1233static void demo_prepare(struct demo *demo) 1234{ 1235 const VkCmdBufferCreateInfo cmd = { 1236 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO, 1237 .pNext = NULL, 1238 .queueNodeIndex = demo->graphics_queue_node_index, 1239 .level = VK_CMD_BUFFER_LEVEL_PRIMARY, 1240 .flags = 0, 1241 }; 1242 VkResult U_ASSERT_ONLY err; 1243 1244 err = vkCreateCommandBuffer(demo->device, &cmd, &demo->draw_cmd); 1245 assert(!err); 1246 1247 demo_prepare_buffers(demo); 1248 demo_prepare_depth(demo); 1249 demo_prepare_textures(demo); 1250 demo_prepare_vertices(demo); 1251 demo_prepare_descriptor_layout(demo); 1252 demo_prepare_pipeline(demo); 1253 demo_prepare_dynamic_states(demo); 1254 1255 demo_prepare_descriptor_pool(demo); 1256 demo_prepare_descriptor_set(demo); 1257 demo->prepared = true; 1258} 1259 1260#ifdef _WIN32 1261static void demo_run(struct demo *demo) 1262{ 1263 if (!demo->prepared) 1264 return; 1265 demo_draw(demo); 1266} 1267 1268// On MS-Windows, make this a global, so it's available to WndProc() 1269struct demo demo; 1270 1271// MS-Windows event handling function: 1272LRESULT CALLBACK WndProc(HWND hWnd, 1273 UINT uMsg, 1274 WPARAM wParam, 1275 LPARAM lParam) 1276{ 1277 char tmp_str[] = APP_LONG_NAME; 1278 1279 switch(uMsg) 1280 { 1281 case WM_CREATE: 1282 return 0; 1283 case WM_CLOSE: 1284 PostQuitMessage(0); 1285 return 0; 1286 case WM_PAINT: 1287 demo_run(&demo); 1288 return 0; 1289 default: 1290 break; 1291 } 1292 return (DefWindowProc(hWnd, uMsg, wParam, lParam)); 1293} 1294 1295static void demo_create_window(struct demo *demo) 1296{ 1297 WNDCLASSEX win_class; 1298 1299 // Initialize the window class structure: 1300 win_class.cbSize = sizeof(WNDCLASSEX); 1301 win_class.style = CS_HREDRAW | CS_VREDRAW; 1302 win_class.lpfnWndProc = WndProc; 1303 win_class.cbClsExtra = 0; 1304 win_class.cbWndExtra = 0; 1305 win_class.hInstance = demo->connection; // hInstance 1306 win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); 1307 win_class.hCursor = LoadCursor(NULL, IDC_ARROW); 1308 win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 1309 win_class.lpszMenuName = NULL; 1310 win_class.lpszClassName = demo->name; 1311 win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO); 1312 // Register window class: 1313 if (!RegisterClassEx(&win_class)) { 1314 // It didn't work, so try to give a useful error: 1315 printf("Unexpected error trying to start the application!\n"); 1316 fflush(stdout); 1317 exit(1); 1318 } 1319 // Create window with the registered class: 1320 RECT wr = { 0, 0, demo->width, demo->height }; 1321 AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); 1322 demo->window = CreateWindowEx(0, 1323 demo->name, // class name 1324 demo->name, // app name 1325 WS_OVERLAPPEDWINDOW | // window style 1326 WS_VISIBLE | 1327 WS_SYSMENU, 1328 100,100, // x/y coords 1329 wr.right-wr.left, // width 1330 wr.bottom-wr.top, // height 1331 NULL, // handle to parent 1332 NULL, // handle to menu 1333 demo->connection, // hInstance 1334 NULL); // no extra parameters 1335 if (!demo->window) { 1336 // It didn't work, so try to give a useful error: 1337 printf("Cannot create a window in which to draw!\n"); 1338 fflush(stdout); 1339 exit(1); 1340 } 1341} 1342#else // _WIN32 1343 1344static void demo_handle_event(struct demo *demo, 1345 const xcb_generic_event_t *event) 1346{ 1347 switch (event->response_type & 0x7f) { 1348 case XCB_EXPOSE: 1349 demo_draw(demo); 1350 break; 1351 case XCB_CLIENT_MESSAGE: 1352 if((*(xcb_client_message_event_t*)event).data.data32[0] == 1353 (*demo->atom_wm_delete_window).atom) { 1354 demo->quit = true; 1355 } 1356 break; 1357 case XCB_KEY_RELEASE: 1358 { 1359 const xcb_key_release_event_t *key = 1360 (const xcb_key_release_event_t *) event; 1361 1362 if (key->detail == 0x9) 1363 demo->quit = true; 1364 } 1365 break; 1366 case XCB_DESTROY_NOTIFY: 1367 demo->quit = true; 1368 break; 1369 default: 1370 break; 1371 } 1372} 1373 1374static void demo_run(struct demo *demo) 1375{ 1376 xcb_flush(demo->connection); 1377 1378 while (!demo->quit) { 1379 xcb_generic_event_t *event; 1380 1381 event = xcb_wait_for_event(demo->connection); 1382 if (event) { 1383 demo_handle_event(demo, event); 1384 free(event); 1385 } 1386 } 1387} 1388 1389static void demo_create_window(struct demo *demo) 1390{ 1391 uint32_t value_mask, value_list[32]; 1392 1393 demo->window = xcb_generate_id(demo->connection); 1394 1395 value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 1396 value_list[0] = demo->screen->black_pixel; 1397 value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | 1398 XCB_EVENT_MASK_EXPOSURE | 1399 XCB_EVENT_MASK_STRUCTURE_NOTIFY; 1400 1401 xcb_create_window(demo->connection, 1402 XCB_COPY_FROM_PARENT, 1403 demo->window, demo->screen->root, 1404 0, 0, demo->width, demo->height, 0, 1405 XCB_WINDOW_CLASS_INPUT_OUTPUT, 1406 demo->screen->root_visual, 1407 value_mask, value_list); 1408 1409 /* Magic code that will send notification when window is destroyed */ 1410 xcb_intern_atom_cookie_t cookie = xcb_intern_atom(demo->connection, 1, 12, 1411 "WM_PROTOCOLS"); 1412 xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(demo->connection, cookie, 0); 1413 1414 xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW"); 1415 demo->atom_wm_delete_window = xcb_intern_atom_reply(demo->connection, cookie2, 0); 1416 1417 xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, 1418 demo->window, (*reply).atom, 4, 32, 1, 1419 &(*demo->atom_wm_delete_window).atom); 1420 free(reply); 1421 1422 xcb_map_window(demo->connection, demo->window); 1423} 1424#endif // _WIN32 1425 1426static void demo_init_vk(struct demo *demo) 1427{ 1428 VkResult err; 1429 char *extension_names[64]; 1430 char *layer_names[64]; 1431 VkExtensionProperties *instance_extensions; 1432 VkLayerProperties *instance_layers; 1433 VkLayerProperties *device_layers; 1434 uint32_t instance_extension_count = 0; 1435 uint32_t instance_layer_count = 0; 1436 uint32_t enabled_extension_count = 0; 1437 uint32_t enabled_layer_count = 0; 1438 1439 /* Look for validation layers */ 1440 bool32_t validation_found = 0; 1441 err = vkGetGlobalLayerProperties(&instance_layer_count, NULL); 1442 assert(!err); 1443 1444 memset(layer_names, 0, sizeof(layer_names)); 1445 instance_layers = malloc(sizeof(VkLayerProperties) * instance_layer_count); 1446 err = vkGetGlobalLayerProperties(&instance_layer_count, instance_layers); 1447 assert(!err); 1448 for (uint32_t i = 0; i < instance_layer_count; i++) { 1449 if (!validation_found && demo->validate && !strcmp("Validation", instance_layers[i].layerName)) { 1450 layer_names[enabled_layer_count++] = "Validation"; 1451 validation_found = 1; 1452 } 1453 assert(enabled_layer_count < 64); 1454 } 1455 if (demo->validate && !validation_found) { 1456 ERR_EXIT("vkGetGlobalLayerProperties failed to find any " 1457 "\"Validation\" layers.\n\n" 1458 "Please look at the Getting Started guide for additional " 1459 "information.\n", 1460 "vkCreateInstance Failure"); 1461 } 1462 1463 err = vkGetGlobalExtensionProperties(NULL, &instance_extension_count, NULL); 1464 assert(!err); 1465 1466 bool32_t WSIextFound = 0; 1467 memset(extension_names, 0, sizeof(extension_names)); 1468 instance_extensions = malloc(sizeof(VkExtensionProperties) * instance_extension_count); 1469 err = vkGetGlobalExtensionProperties(NULL, &instance_extension_count, instance_extensions); 1470 assert(!err); 1471 for (uint32_t i = 0; i < instance_extension_count; i++) { 1472 if (!strcmp(VK_WSI_LUNARG_EXTENSION_NAME, instance_extensions[i].extName)) { 1473 WSIextFound = 1; 1474 extension_names[enabled_extension_count++] = VK_WSI_LUNARG_EXTENSION_NAME; 1475 } 1476 if (!strcmp(DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extName)) { 1477 if (demo->validate) { 1478 extension_names[enabled_extension_count++] = DEBUG_REPORT_EXTENSION_NAME; 1479 } 1480 } 1481 assert(enabled_extension_count < 64); 1482 } 1483 if (!WSIextFound) { 1484 ERR_EXIT("vkGetGlobalExtensionProperties failed to find the " 1485 "\"VK_WSI_LunarG\" extension.\n\nDo you have a compatible " 1486 "Vulkan installable client driver (ICD) installed?\nPlease " 1487 "look at the Getting Started guide for additional " 1488 "information.\n", 1489 "vkCreateInstance Failure"); 1490 } 1491 const VkApplicationInfo app = { 1492 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 1493 .pNext = NULL, 1494 .pAppName = APP_SHORT_NAME, 1495 .appVersion = 0, 1496 .pEngineName = APP_SHORT_NAME, 1497 .engineVersion = 0, 1498 .apiVersion = VK_API_VERSION, 1499 }; 1500 VkInstanceCreateInfo inst_info = { 1501 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 1502 .pNext = NULL, 1503 .pAppInfo = &app, 1504 .pAllocCb = NULL, 1505 .layerCount = enabled_layer_count, 1506 .ppEnabledLayerNames = (const char *const*) layer_names, 1507 .extensionCount = enabled_extension_count, 1508 .ppEnabledExtensionNames = (const char *const*) extension_names, 1509 }; 1510 const VkDeviceQueueCreateInfo queue = { 1511 .queueNodeIndex = 0, 1512 .queueCount = 1, 1513 }; 1514 1515 uint32_t gpu_count; 1516 uint32_t i; 1517 uint32_t queue_count; 1518 1519 err = vkCreateInstance(&inst_info, &demo->inst); 1520 if (err == VK_ERROR_INCOMPATIBLE_DRIVER) { 1521 ERR_EXIT("Cannot find a compatible Vulkan installable client driver " 1522 "(ICD).\n\nPlease look at the Getting Started guide for " 1523 "additional information.\n", 1524 "vkCreateInstance Failure"); 1525 } else if (err == VK_ERROR_INVALID_EXTENSION) { 1526 ERR_EXIT("Cannot find a specified extension library" 1527 ".\nMake sure your layers path is set appropriately\n", 1528 "vkCreateInstance Failure"); 1529 } else if (err) { 1530 ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan " 1531 "installable client driver (ICD) installed?\nPlease look at " 1532 "the Getting Started guide for additional information.\n", 1533 "vkCreateInstance Failure"); 1534 } 1535 1536 free(instance_layers); 1537 free(instance_extensions); 1538 1539 gpu_count = 1; 1540 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, &demo->gpu); 1541 assert(!err && gpu_count == 1); 1542 1543 /* Look for validation layers */ 1544 validation_found = 0; 1545 enabled_layer_count = 0; 1546 uint32_t device_layer_count = 0; 1547 err = vkGetPhysicalDeviceLayerProperties(demo->gpu, &device_layer_count, NULL); 1548 assert(!err); 1549 1550 memset(layer_names, 0, sizeof(layer_names)); 1551 device_layers = malloc(sizeof(VkLayerProperties) * device_layer_count); 1552 err = vkGetPhysicalDeviceLayerProperties(demo->gpu, &device_layer_count, device_layers); 1553 assert(!err); 1554 for (uint32_t i = 0; i < device_layer_count; i++) { 1555 if (!validation_found && demo->validate && 1556 !strcmp("Validation", device_layers[i].layerName)) { 1557 layer_names[enabled_layer_count++] = "Validation"; 1558 validation_found = 1; 1559 } 1560 assert(enabled_layer_count < 64); 1561 } 1562 if (demo->validate && !validation_found) { 1563 ERR_EXIT("vkGetGlobalLayerProperties failed to find any " 1564 "\"Validation\" layers.\n\n" 1565 "Please look at the Getting Started guide for additional " 1566 "information.\n", 1567 "vkCreateInstance Failure"); 1568 } 1569 1570 /* Don't need any device extensions */ 1571 /* TODO: WSI device extension will go here eventually */ 1572 1573 VkDeviceCreateInfo device = { 1574 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 1575 .pNext = NULL, 1576 .queueRecordCount = 1, 1577 .pRequestedQueues = &queue, 1578 .layerCount = enabled_layer_count, 1579 .ppEnabledLayerNames = (const char*const*) layer_names, 1580 .extensionCount = 0, 1581 .ppEnabledExtensionNames = NULL, 1582 .flags = 0, 1583 }; 1584 1585 if (demo->validate) { 1586 demo->dbgCreateMsgCallback = vkGetInstanceProcAddr((VkPhysicalDevice) NULL, "vkDbgCreateMsgCallback"); 1587 if (!demo->dbgCreateMsgCallback) { 1588 ERR_EXIT("GetProcAddr: Unable to find vkDbgCreateMsgCallback\n", 1589 "vkGetProcAddr Failure"); 1590 } 1591 err = demo->dbgCreateMsgCallback( 1592 demo->inst, 1593 VK_DBG_REPORT_ERROR_BIT | VK_DBG_REPORT_WARN_BIT, 1594 dbgFunc, NULL, 1595 &demo->msg_callback); 1596 switch (err) { 1597 case VK_SUCCESS: 1598 break; 1599 case VK_ERROR_INVALID_POINTER: 1600 ERR_EXIT("dbgCreateMsgCallback: Invalid pointer\n", 1601 "dbgCreateMsgCallback Failure"); 1602 break; 1603 case VK_ERROR_OUT_OF_HOST_MEMORY: 1604 ERR_EXIT("dbgCreateMsgCallback: out of host memory\n", 1605 "dbgCreateMsgCallback Failure"); 1606 break; 1607 default: 1608 ERR_EXIT("dbgCreateMsgCallback: unknown failure\n", 1609 "dbgCreateMsgCallback Failure"); 1610 break; 1611 } 1612 } 1613 1614 err = vkCreateDevice(demo->gpu, &device, &demo->device); 1615 assert(!err); 1616 1617 free(device_layers); 1618 1619 GET_DEVICE_PROC_ADDR(demo->device, CreateSwapChainWSI); 1620 GET_DEVICE_PROC_ADDR(demo->device, CreateSwapChainWSI); 1621 GET_DEVICE_PROC_ADDR(demo->device, DestroySwapChainWSI); 1622 GET_DEVICE_PROC_ADDR(demo->device, GetSwapChainInfoWSI); 1623 GET_DEVICE_PROC_ADDR(demo->device, QueuePresentWSI); 1624 1625 err = vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props); 1626 assert(!err); 1627 1628 err = vkGetPhysicalDeviceQueueCount(demo->gpu, &queue_count); 1629 assert(!err); 1630 1631 demo->queue_props = (VkPhysicalDeviceQueueProperties *) malloc(queue_count * sizeof(VkPhysicalDeviceQueueProperties)); 1632 err = vkGetPhysicalDeviceQueueProperties(demo->gpu, queue_count, demo->queue_props); 1633 assert(!err); 1634 assert(queue_count >= 1); 1635 1636 // Graphics queue and MemMgr queue can be separate. 1637 // TODO: Add support for separate queues, including synchronization, 1638 // and appropriate tracking for QueueSubmit 1639 for (i = 0; i < queue_count; i++) { 1640 if (demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) 1641 break; 1642 } 1643 assert(i < queue_count); 1644 demo->graphics_queue_node_index = i; 1645 1646 err = vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 1647 0, &demo->queue); 1648 assert(!err); 1649 1650 // for now hardcode format till get WSI support 1651 demo->format = VK_FORMAT_B8G8R8A8_UNORM; 1652 1653 // Get Memory information and properties 1654 err = vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties); 1655 assert(!err); 1656} 1657 1658static void demo_init_connection(struct demo *demo) 1659{ 1660#ifndef _WIN32 1661 const xcb_setup_t *setup; 1662 xcb_screen_iterator_t iter; 1663 int scr; 1664 1665 demo->connection = xcb_connect(NULL, &scr); 1666 if (demo->connection == NULL) { 1667 printf("Cannot find a compatible Vulkan installable client driver " 1668 "(ICD).\nExiting ...\n"); 1669 fflush(stdout); 1670 exit(1); 1671 } 1672 1673 setup = xcb_get_setup(demo->connection); 1674 iter = xcb_setup_roots_iterator(setup); 1675 while (scr-- > 0) 1676 xcb_screen_next(&iter); 1677 1678 demo->screen = iter.data; 1679#endif // _WIN32 1680} 1681 1682#ifdef _WIN32 1683static void demo_init(struct demo *demo, HINSTANCE hInstance, LPSTR pCmdLine) 1684#else // _WIN32 1685static void demo_init(struct demo *demo, const int argc, const char *argv[]) 1686#endif // _WIN32 1687{ 1688 bool argv_error = false; 1689 1690 memset(demo, 0, sizeof(*demo)); 1691 1692#ifdef _WIN32 1693 demo->connection = hInstance; 1694 strncpy(demo->name, APP_SHORT_NAME, APP_NAME_STR_LEN); 1695 1696 if (strncmp(pCmdLine, "--use_staging", strlen("--use_staging")) == 0) 1697 demo->use_staging_buffer = true; 1698 else if (strncmp(pCmdLine, "--use_glsl", strlen("--use_glsl")) == 0) 1699 demo->use_glsl = true; 1700 else if (strlen(pCmdLine) != 0) { 1701 fprintf(stderr, "Do not recognize argument \"%s\".\n", pCmdLine); 1702 argv_error = true; 1703 } 1704#else // _WIN32 1705 for (int i = 0; i < argc; i++) { 1706 if (strncmp(argv[i], "--use_staging", strlen("--use_staging")) == 0) 1707 demo->use_staging_buffer = true; 1708 else if (strncmp(argv[i], "--use_glsl", strlen("--use_glsl")) == 0) 1709 demo->use_glsl = true; 1710 } 1711#endif // _WIN32 1712 if (argv_error) { 1713 fprintf(stderr, "Usage:\n %s [--use_staging]\n", APP_SHORT_NAME); 1714 fflush(stderr); 1715 exit(1); 1716 } 1717 1718 demo_init_connection(demo); 1719 demo_init_vk(demo); 1720 1721 demo->width = 300; 1722 demo->height = 300; 1723} 1724 1725static void demo_cleanup(struct demo *demo) 1726{ 1727 uint32_t i; 1728 1729 vkDestroyObject(demo->device, VK_OBJECT_TYPE_DESCRIPTOR_SET, demo->desc_set); 1730 vkDestroyObject(demo->device, VK_OBJECT_TYPE_DESCRIPTOR_POOL, demo->desc_pool); 1731 1732 if (demo->setup_cmd) { 1733 vkDestroyObject(demo->device, VK_OBJECT_TYPE_COMMAND_BUFFER, demo->setup_cmd); 1734 } 1735 vkDestroyObject(demo->device, VK_OBJECT_TYPE_COMMAND_BUFFER, demo->draw_cmd); 1736 1737 vkDestroyObject(demo->device, VK_OBJECT_TYPE_DYNAMIC_VP_STATE, demo->viewport); 1738 vkDestroyObject(demo->device, VK_OBJECT_TYPE_DYNAMIC_RS_STATE, demo->raster); 1739 vkDestroyObject(demo->device, VK_OBJECT_TYPE_DYNAMIC_CB_STATE, demo->color_blend); 1740 vkDestroyObject(demo->device, VK_OBJECT_TYPE_DYNAMIC_DS_STATE, demo->depth_stencil); 1741 1742 vkDestroyObject(demo->device, VK_OBJECT_TYPE_PIPELINE, demo->pipeline); 1743 vkDestroyObject(demo->device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, demo->pipeline_layout); 1744 vkDestroyObject(demo->device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, demo->desc_layout); 1745 1746 vkDestroyObject(demo->device, VK_OBJECT_TYPE_BUFFER, demo->vertices.buf); 1747 vkFreeMemory(demo->device, demo->vertices.mem); 1748 1749 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1750 vkDestroyObject(demo->device, VK_OBJECT_TYPE_IMAGE_VIEW, demo->textures[i].view); 1751 vkDestroyObject(demo->device, VK_OBJECT_TYPE_IMAGE, demo->textures[i].image); 1752 vkFreeMemory(demo->device, demo->textures[i].mem); 1753 vkDestroyObject(demo->device, VK_OBJECT_TYPE_SAMPLER, demo->textures[i].sampler); 1754 } 1755 1756 vkDestroyObject(demo->device, VK_OBJECT_TYPE_DEPTH_STENCIL_VIEW, demo->depth.view); 1757 vkDestroyObject(demo->device, VK_OBJECT_TYPE_IMAGE, demo->depth.image); 1758 vkFreeMemory(demo->device, demo->depth.mem); 1759 1760 for (i = 0; i < DEMO_BUFFER_COUNT; i++) { 1761 vkDestroyObject(demo->device, VK_OBJECT_TYPE_COLOR_ATTACHMENT_VIEW, demo->buffers[i].view); 1762 } 1763 demo->fpDestroySwapChainWSI(demo->swap_chain); 1764 1765 vkDestroyDevice(demo->device); 1766 vkDestroyInstance(demo->inst); 1767 1768#ifndef _WIN32 1769 xcb_destroy_window(demo->connection, demo->window); 1770 xcb_disconnect(demo->connection); 1771#endif // _WIN32 1772} 1773 1774#ifdef _WIN32 1775int APIENTRY WinMain(HINSTANCE hInstance, 1776 HINSTANCE hPrevInstance, 1777 LPSTR pCmdLine, 1778 int nCmdShow) 1779{ 1780 MSG msg; // message 1781 bool done; // flag saying when app is complete 1782 1783 demo_init(&demo, hInstance, pCmdLine); 1784 demo_create_window(&demo); 1785 1786 demo_prepare(&demo); 1787 1788 done = false; //initialize loop condition variable 1789 /* main message loop*/ 1790 while(!done) 1791 { 1792 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); 1793 if (msg.message == WM_QUIT) //check for a quit message 1794 { 1795 done = true; //if found, quit app 1796 } 1797 else 1798 { 1799 /* Translate and dispatch to event queue*/ 1800 TranslateMessage(&msg); 1801 DispatchMessage(&msg); 1802 } 1803 } 1804 1805 demo_cleanup(&demo); 1806 1807 return (int) msg.wParam; 1808} 1809#else // _WIN32 1810int main(const int argc, const char *argv[]) 1811{ 1812 struct demo demo; 1813 1814 demo_init(&demo, argc, argv); 1815 demo_create_window(&demo); 1816 1817 demo_prepare(&demo); 1818 demo_run(&demo); 1819 1820 demo_cleanup(&demo); 1821 1822 return 0; 1823} 1824#endif // _WIN32 1825