tri.c revision d38dcc92057e23405c3accf874c91e988237f7ed
1/* 2 * Draw a textured triangle with depth testing. This is written against Intel 3 * ICD. It does not do state transition nor object memory binding like it 4 * should. It also does no error checking. 5 */ 6 7#include <stdio.h> 8#include <stdlib.h> 9#include <string.h> 10#include <stdbool.h> 11#include <assert.h> 12 13#include <xcb/xcb.h> 14#include <vulkan.h> 15#include <vkDbg.h> 16#include <vkWsiX11Ext.h> 17 18#include "icd-spv.h" 19 20#define DEMO_BUFFER_COUNT 2 21#define DEMO_TEXTURE_COUNT 1 22#define VERTEX_BUFFER_BIND_ID 0 23 24struct texture_object { 25 VK_SAMPLER sampler; 26 27 VK_IMAGE image; 28 VK_IMAGE_LAYOUT imageLayout; 29 30 uint32_t num_mem; 31 VK_GPU_MEMORY *mem; 32 VK_IMAGE_VIEW view; 33 int32_t tex_width, tex_height; 34}; 35 36struct demo { 37 xcb_connection_t *connection; 38 xcb_screen_t *screen; 39 40 VK_INSTANCE inst; 41 VK_PHYSICAL_GPU gpu; 42 VK_DEVICE device; 43 VK_QUEUE queue; 44 VK_PHYSICAL_GPU_PROPERTIES *gpu_props; 45 VK_PHYSICAL_GPU_QUEUE_PROPERTIES *queue_props; 46 uint32_t graphics_queue_node_index; 47 48 int width, height; 49 VK_FORMAT format; 50 51 struct { 52 VK_IMAGE image; 53 VK_GPU_MEMORY mem; 54 55 VK_COLOR_ATTACHMENT_VIEW view; 56 VK_FENCE fence; 57 } buffers[DEMO_BUFFER_COUNT]; 58 59 struct { 60 VK_FORMAT format; 61 62 VK_IMAGE image; 63 uint32_t num_mem; 64 VK_GPU_MEMORY *mem; 65 VK_DEPTH_STENCIL_VIEW view; 66 } depth; 67 68 struct texture_object textures[DEMO_TEXTURE_COUNT]; 69 70 struct { 71 VK_BUFFER buf; 72 uint32_t num_mem; 73 VK_GPU_MEMORY *mem; 74 75 VK_PIPELINE_VERTEX_INPUT_CREATE_INFO vi; 76 VK_VERTEX_INPUT_BINDING_DESCRIPTION vi_bindings[1]; 77 VK_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION vi_attrs[2]; 78 } vertices; 79 80 VK_CMD_BUFFER cmd; // Buffer for initialization commands 81 VK_DESCRIPTOR_SET_LAYOUT_CHAIN desc_layout_chain; 82 VK_DESCRIPTOR_SET_LAYOUT desc_layout; 83 VK_PIPELINE pipeline; 84 85 VK_DYNAMIC_VP_STATE_OBJECT viewport; 86 VK_DYNAMIC_RS_STATE_OBJECT raster; 87 VK_DYNAMIC_CB_STATE_OBJECT color_blend; 88 VK_DYNAMIC_DS_STATE_OBJECT depth_stencil; 89 90 VK_DESCRIPTOR_POOL desc_pool; 91 VK_DESCRIPTOR_SET desc_set; 92 93 xcb_window_t window; 94 xcb_intern_atom_reply_t *atom_wm_delete_window; 95 96 bool quit; 97 bool use_staging_buffer; 98 uint32_t current_buffer; 99}; 100 101static void demo_flush_init_cmd(struct demo *demo) 102{ 103 VK_RESULT err; 104 105 if (demo->cmd == VK_NULL_HANDLE) 106 return; 107 108 err = vkEndCommandBuffer(demo->cmd); 109 assert(!err); 110 111 const VK_CMD_BUFFER cmd_bufs[] = { demo->cmd }; 112 113 err = vkQueueSubmit(demo->queue, 1, cmd_bufs, VK_NULL_HANDLE); 114 assert(!err); 115 116 err = vkQueueWaitIdle(demo->queue); 117 assert(!err); 118 119 vkDestroyObject(demo->cmd); 120 demo->cmd = VK_NULL_HANDLE; 121} 122 123static void demo_add_mem_refs( 124 struct demo *demo, 125 int num_refs, VK_GPU_MEMORY *mem) 126{ 127 for (int i = 0; i < num_refs; i++) { 128 vkQueueAddMemReference(demo->queue, mem[i]); 129 } 130} 131 132static void demo_remove_mem_refs( 133 struct demo *demo, 134 int num_refs, VK_GPU_MEMORY *mem) 135{ 136 for (int i = 0; i < num_refs; i++) { 137 vkQueueRemoveMemReference(demo->queue, mem[i]); 138 } 139} 140 141static void demo_set_image_layout( 142 struct demo *demo, 143 VK_IMAGE image, 144 VK_IMAGE_LAYOUT old_image_layout, 145 VK_IMAGE_LAYOUT new_image_layout) 146{ 147 VK_RESULT err; 148 149 if (demo->cmd == VK_NULL_HANDLE) { 150 const VK_CMD_BUFFER_CREATE_INFO cmd = { 151 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO, 152 .pNext = NULL, 153 .queueNodeIndex = demo->graphics_queue_node_index, 154 .flags = 0, 155 }; 156 157 err = vkCreateCommandBuffer(demo->device, &cmd, &demo->cmd); 158 assert(!err); 159 160 VK_CMD_BUFFER_BEGIN_INFO cmd_buf_info = { 161 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, 162 .pNext = NULL, 163 .flags = VK_CMD_BUFFER_OPTIMIZE_GPU_SMALL_BATCH_BIT | 164 VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT, 165 }; 166 err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info); 167 } 168 169 VK_IMAGE_MEMORY_BARRIER image_memory_barrier = { 170 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 171 .pNext = NULL, 172 .outputMask = 0, 173 .inputMask = 0, 174 .oldLayout = old_image_layout, 175 .newLayout = new_image_layout, 176 .image = image, 177 .subresourceRange = { VK_IMAGE_ASPECT_COLOR, 0, 1, 0, 0 } 178 }; 179 180 if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL) { 181 /* Make sure anything that was copying from this image has completed */ 182 image_memory_barrier.inputMask = VK_MEMORY_INPUT_COPY_BIT; 183 } 184 185 if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 186 /* Make sure any Copy or CPU writes to image are flushed */ 187 image_memory_barrier.outputMask = VK_MEMORY_OUTPUT_COPY_BIT | VK_MEMORY_OUTPUT_CPU_WRITE_BIT; 188 } 189 190 VK_IMAGE_MEMORY_BARRIER *pmemory_barrier = &image_memory_barrier; 191 192 VK_PIPE_EVENT set_events[] = { VK_PIPE_EVENT_TOP_OF_PIPE }; 193 194 VK_PIPELINE_BARRIER pipeline_barrier; 195 pipeline_barrier.sType = VK_STRUCTURE_TYPE_PIPELINE_BARRIER; 196 pipeline_barrier.pNext = NULL; 197 pipeline_barrier.eventCount = 1; 198 pipeline_barrier.pEvents = set_events; 199 pipeline_barrier.waitEvent = VK_WAIT_EVENT_TOP_OF_PIPE; 200 pipeline_barrier.memBarrierCount = 1; 201 pipeline_barrier.ppMemBarriers = (const void **)&pmemory_barrier; 202 203 vkCmdPipelineBarrier(demo->cmd, &pipeline_barrier); 204} 205 206static void demo_draw_build_cmd(struct demo *demo) 207{ 208 const VK_COLOR_ATTACHMENT_BIND_INFO color_attachment = { 209 .view = demo->buffers[demo->current_buffer].view, 210 .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 211 }; 212 const VK_DEPTH_STENCIL_BIND_INFO depth_stencil = { 213 .view = demo->depth.view, 214 .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, 215 }; 216 const VK_CLEAR_COLOR clear_color = { 217 .color.floatColor = { 0.2f, 0.2f, 0.2f, 0.2f }, 218 .useRawValue = false, 219 }; 220 const float clear_depth = 0.9f; 221 VK_IMAGE_SUBRESOURCE_RANGE clear_range; 222 VK_CMD_BUFFER_BEGIN_INFO cmd_buf_info = { 223 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, 224 .pNext = NULL, 225 .flags = VK_CMD_BUFFER_OPTIMIZE_GPU_SMALL_BATCH_BIT | 226 VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT, 227 }; 228 VK_RESULT err; 229 VK_ATTACHMENT_LOAD_OP load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 230 VK_ATTACHMENT_STORE_OP store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE; 231 const VK_FRAMEBUFFER_CREATE_INFO fb_info = { 232 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 233 .pNext = NULL, 234 .colorAttachmentCount = 1, 235 .pColorAttachments = (VK_COLOR_ATTACHMENT_BIND_INFO*) &color_attachment, 236 .pDepthStencilAttachment = (VK_DEPTH_STENCIL_BIND_INFO*) &depth_stencil, 237 .sampleCount = 1, 238 .width = demo->width, 239 .height = demo->height, 240 .layers = 1, 241 }; 242 VK_RENDER_PASS_CREATE_INFO rp_info; 243 VK_RENDER_PASS_BEGIN rp_begin; 244 245 memset(&rp_info, 0 , sizeof(rp_info)); 246 err = vkCreateFramebuffer(demo->device, &fb_info, &rp_begin.framebuffer); 247 assert(!err); 248 rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; 249 rp_info.renderArea.extent.width = demo->width; 250 rp_info.renderArea.extent.height = demo->height; 251 rp_info.colorAttachmentCount = fb_info.colorAttachmentCount; 252 rp_info.pColorFormats = &demo->format; 253 rp_info.pColorLayouts = &color_attachment.layout; 254 rp_info.pColorLoadOps = &load_op; 255 rp_info.pColorStoreOps = &store_op; 256 rp_info.pColorLoadClearValues = &clear_color; 257 rp_info.depthStencilFormat = VK_FMT_D16_UNORM; 258 rp_info.depthStencilLayout = depth_stencil.layout; 259 rp_info.depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 260 rp_info.depthLoadClearValue = clear_depth; 261 rp_info.depthStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 262 rp_info.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 263 rp_info.stencilLoadClearValue = 0; 264 rp_info.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 265 err = vkCreateRenderPass(demo->device, &rp_info, &(rp_begin.renderPass)); 266 assert(!err); 267 268 err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info); 269 assert(!err); 270 271 vkCmdBindPipeline(demo->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, 272 demo->pipeline); 273 vkCmdBindDescriptorSets(demo->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, 274 demo->desc_layout_chain, 0, 1, & demo->desc_set, NULL); 275 276 vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_VIEWPORT, demo->viewport); 277 vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_RASTER, demo->raster); 278 vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_COLOR_BLEND, 279 demo->color_blend); 280 vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_DEPTH_STENCIL, 281 demo->depth_stencil); 282 283 284 vkCmdBindVertexBuffer(demo->cmd, demo->vertices.buf, 0, VERTEX_BUFFER_BIND_ID); 285 286 vkCmdBeginRenderPass(demo->cmd, &rp_begin); 287 clear_range.aspect = VK_IMAGE_ASPECT_COLOR; 288 clear_range.baseMipLevel = 0; 289 clear_range.mipLevels = 1; 290 clear_range.baseArraySlice = 0; 291 clear_range.arraySize = 1; 292 vkCmdClearColorImage(demo->cmd, 293 demo->buffers[demo->current_buffer].image, 294 VK_IMAGE_LAYOUT_CLEAR_OPTIMAL, 295 clear_color, 1, &clear_range); 296 297 clear_range.aspect = VK_IMAGE_ASPECT_DEPTH; 298 vkCmdClearDepthStencil(demo->cmd, 299 demo->depth.image, VK_IMAGE_LAYOUT_CLEAR_OPTIMAL, 300 clear_depth, 0, 1, &clear_range); 301 302 vkCmdDraw(demo->cmd, 0, 3, 0, 1); 303 vkCmdEndRenderPass(demo->cmd, rp_begin.renderPass); 304 305 err = vkEndCommandBuffer(demo->cmd); 306 assert(!err); 307 308 vkDestroyObject(rp_begin.renderPass); 309 vkDestroyObject(rp_begin.framebuffer); 310} 311 312static void demo_draw(struct demo *demo) 313{ 314 const VK_WSI_X11_PRESENT_INFO present = { 315 .destWindow = demo->window, 316 .srcImage = demo->buffers[demo->current_buffer].image, 317 }; 318 VK_FENCE fence = demo->buffers[demo->current_buffer].fence; 319 VK_RESULT err; 320 321 demo_draw_build_cmd(demo); 322 323 err = vkWaitForFences(demo->device, 1, &fence, VK_TRUE, ~((uint64_t) 0)); 324 assert(err == VK_SUCCESS || err == VK_ERROR_UNAVAILABLE); 325 326 err = vkQueueSubmit(demo->queue, 1, &demo->cmd, VK_NULL_HANDLE); 327 assert(!err); 328 329 err = vkWsiX11QueuePresent(demo->queue, &present, fence); 330 assert(!err); 331 332 demo->current_buffer = (demo->current_buffer + 1) % DEMO_BUFFER_COUNT; 333} 334 335static void demo_prepare_buffers(struct demo *demo) 336{ 337 const VK_WSI_X11_PRESENTABLE_IMAGE_CREATE_INFO presentable_image = { 338 .format = demo->format, 339 .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 340 .extent = { 341 .width = demo->width, 342 .height = demo->height, 343 }, 344 .flags = 0, 345 }; 346 const VK_FENCE_CREATE_INFO fence = { 347 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 348 .pNext = NULL, 349 .flags = 0, 350 }; 351 VK_RESULT err; 352 uint32_t i; 353 354 for (i = 0; i < DEMO_BUFFER_COUNT; i++) { 355 VK_COLOR_ATTACHMENT_VIEW_CREATE_INFO color_attachment_view = { 356 .sType = VK_STRUCTURE_TYPE_COLOR_ATTACHMENT_VIEW_CREATE_INFO, 357 .pNext = NULL, 358 .format = demo->format, 359 .mipLevel = 0, 360 .baseArraySlice = 0, 361 .arraySize = 1, 362 }; 363 364 err = vkWsiX11CreatePresentableImage(demo->device, &presentable_image, 365 &demo->buffers[i].image, &demo->buffers[i].mem); 366 assert(!err); 367 demo_add_mem_refs(demo, 1, &demo->buffers[i].mem); 368 demo_set_image_layout(demo, demo->buffers[i].image, 369 VK_IMAGE_LAYOUT_UNDEFINED, 370 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 371 372 color_attachment_view.image = demo->buffers[i].image; 373 374 err = vkCreateColorAttachmentView(demo->device, 375 &color_attachment_view, &demo->buffers[i].view); 376 assert(!err); 377 378 err = vkCreateFence(demo->device, 379 &fence, &demo->buffers[i].fence); 380 assert(!err); 381 } 382 383 demo->current_buffer = 0; 384} 385 386static void demo_prepare_depth(struct demo *demo) 387{ 388 const VK_FORMAT depth_format = VK_FMT_D16_UNORM; 389 const VK_IMAGE_CREATE_INFO image = { 390 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 391 .pNext = NULL, 392 .imageType = VK_IMAGE_2D, 393 .format = depth_format, 394 .extent = { demo->width, demo->height, 1 }, 395 .mipLevels = 1, 396 .arraySize = 1, 397 .samples = 1, 398 .tiling = VK_OPTIMAL_TILING, 399 .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_BIT, 400 .flags = 0, 401 }; 402 VK_MEMORY_ALLOC_IMAGE_INFO img_alloc = { 403 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_IMAGE_INFO, 404 .pNext = NULL, 405 }; 406 VK_MEMORY_ALLOC_INFO mem_alloc = { 407 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 408 .pNext = &img_alloc, 409 .allocationSize = 0, 410 .memProps = VK_MEMORY_PROPERTY_GPU_ONLY, 411 .memType = VK_MEMORY_TYPE_IMAGE, 412 .memPriority = VK_MEMORY_PRIORITY_NORMAL, 413 }; 414 VK_DEPTH_STENCIL_VIEW_CREATE_INFO view = { 415 .sType = VK_STRUCTURE_TYPE_DEPTH_STENCIL_VIEW_CREATE_INFO, 416 .pNext = NULL, 417 .image = VK_NULL_HANDLE, 418 .mipLevel = 0, 419 .baseArraySlice = 0, 420 .arraySize = 1, 421 .flags = 0, 422 }; 423 424 VK_MEMORY_REQUIREMENTS *mem_reqs; 425 size_t mem_reqs_size = sizeof(VK_MEMORY_REQUIREMENTS); 426 VK_IMAGE_MEMORY_REQUIREMENTS img_reqs; 427 size_t img_reqs_size = sizeof(VK_IMAGE_MEMORY_REQUIREMENTS); 428 VK_RESULT err; 429 uint32_t num_allocations = 0; 430 size_t num_alloc_size = sizeof(num_allocations); 431 432 demo->depth.format = depth_format; 433 434 /* create image */ 435 err = vkCreateImage(demo->device, &image, 436 &demo->depth.image); 437 assert(!err); 438 439 err = vkGetObjectInfo(demo->depth.image, VK_INFO_TYPE_MEMORY_ALLOCATION_COUNT, &num_alloc_size, &num_allocations); 440 assert(!err && num_alloc_size == sizeof(num_allocations)); 441 mem_reqs = malloc(num_allocations * sizeof(VK_MEMORY_REQUIREMENTS)); 442 demo->depth.mem = malloc(num_allocations * sizeof(VK_GPU_MEMORY)); 443 demo->depth.num_mem = num_allocations; 444 err = vkGetObjectInfo(demo->depth.image, 445 VK_INFO_TYPE_MEMORY_REQUIREMENTS, 446 &mem_reqs_size, mem_reqs); 447 assert(!err && mem_reqs_size == num_allocations * sizeof(VK_MEMORY_REQUIREMENTS)); 448 err = vkGetObjectInfo(demo->depth.image, 449 VK_INFO_TYPE_IMAGE_MEMORY_REQUIREMENTS, 450 &img_reqs_size, &img_reqs); 451 assert(!err && img_reqs_size == sizeof(VK_IMAGE_MEMORY_REQUIREMENTS)); 452 img_alloc.usage = img_reqs.usage; 453 img_alloc.formatClass = img_reqs.formatClass; 454 img_alloc.samples = img_reqs.samples; 455 for (uint32_t i = 0; i < num_allocations; i ++) { 456 mem_alloc.allocationSize = mem_reqs[i].size; 457 458 /* allocate memory */ 459 err = vkAllocMemory(demo->device, &mem_alloc, 460 &(demo->depth.mem[i])); 461 assert(!err); 462 463 /* bind memory */ 464 err = vkBindObjectMemory(demo->depth.image, i, 465 demo->depth.mem[i], 0); 466 assert(!err); 467 } 468 469 demo_set_image_layout(demo, demo->depth.image, 470 VK_IMAGE_LAYOUT_UNDEFINED, 471 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); 472 473 demo_add_mem_refs(demo, demo->depth.num_mem, demo->depth.mem); 474 475 /* create image view */ 476 view.image = demo->depth.image; 477 err = vkCreateDepthStencilView(demo->device, &view, 478 &demo->depth.view); 479 assert(!err); 480} 481 482static void demo_prepare_texture_image(struct demo *demo, 483 const uint32_t *tex_colors, 484 struct texture_object *tex_obj, 485 VK_IMAGE_TILING tiling, 486 VK_FLAGS mem_props) 487{ 488 const VK_FORMAT tex_format = VK_FMT_B8G8R8A8_UNORM; 489 const int32_t tex_width = 2; 490 const int32_t tex_height = 2; 491 VK_RESULT err; 492 493 tex_obj->tex_width = tex_width; 494 tex_obj->tex_height = tex_height; 495 496 const VK_IMAGE_CREATE_INFO image_create_info = { 497 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 498 .pNext = NULL, 499 .imageType = VK_IMAGE_2D, 500 .format = tex_format, 501 .extent = { tex_width, tex_height, 1 }, 502 .mipLevels = 1, 503 .arraySize = 1, 504 .samples = 1, 505 .tiling = tiling, 506 .usage = VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT, 507 .flags = 0, 508 }; 509 VK_MEMORY_ALLOC_IMAGE_INFO img_alloc = { 510 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_IMAGE_INFO, 511 .pNext = NULL, 512 }; 513 VK_MEMORY_ALLOC_INFO mem_alloc = { 514 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 515 .pNext = &img_alloc, 516 .allocationSize = 0, 517 .memProps = mem_props, 518 .memType = VK_MEMORY_TYPE_IMAGE, 519 .memPriority = VK_MEMORY_PRIORITY_NORMAL, 520 }; 521 522 VK_MEMORY_REQUIREMENTS *mem_reqs; 523 size_t mem_reqs_size = sizeof(VK_MEMORY_REQUIREMENTS); 524 VK_IMAGE_MEMORY_REQUIREMENTS img_reqs; 525 size_t img_reqs_size = sizeof(VK_IMAGE_MEMORY_REQUIREMENTS); 526 uint32_t num_allocations = 0; 527 size_t num_alloc_size = sizeof(num_allocations); 528 529 err = vkCreateImage(demo->device, &image_create_info, 530 &tex_obj->image); 531 assert(!err); 532 533 err = vkGetObjectInfo(tex_obj->image, 534 VK_INFO_TYPE_MEMORY_ALLOCATION_COUNT, 535 &num_alloc_size, &num_allocations); 536 assert(!err && num_alloc_size == sizeof(num_allocations)); 537 mem_reqs = malloc(num_allocations * sizeof(VK_MEMORY_REQUIREMENTS)); 538 tex_obj->mem = malloc(num_allocations * sizeof(VK_GPU_MEMORY)); 539 err = vkGetObjectInfo(tex_obj->image, 540 VK_INFO_TYPE_MEMORY_REQUIREMENTS, 541 &mem_reqs_size, mem_reqs); 542 assert(!err && mem_reqs_size == num_allocations * sizeof(VK_MEMORY_REQUIREMENTS)); 543 err = vkGetObjectInfo(tex_obj->image, 544 VK_INFO_TYPE_IMAGE_MEMORY_REQUIREMENTS, 545 &img_reqs_size, &img_reqs); 546 assert(!err && img_reqs_size == sizeof(VK_IMAGE_MEMORY_REQUIREMENTS)); 547 img_alloc.usage = img_reqs.usage; 548 img_alloc.formatClass = img_reqs.formatClass; 549 img_alloc.samples = img_reqs.samples; 550 mem_alloc.memProps = VK_MEMORY_PROPERTY_CPU_VISIBLE_BIT; 551 for (uint32_t j = 0; j < num_allocations; j ++) { 552 mem_alloc.allocationSize = mem_reqs[j].size; 553 mem_alloc.memType = mem_reqs[j].memType; 554 555 /* allocate memory */ 556 err = vkAllocMemory(demo->device, &mem_alloc, 557 &(tex_obj->mem[j])); 558 assert(!err); 559 560 /* bind memory */ 561 err = vkBindObjectMemory(tex_obj->image, j, tex_obj->mem[j], 0); 562 assert(!err); 563 } 564 free(mem_reqs); 565 mem_reqs = NULL; 566 567 tex_obj->num_mem = num_allocations; 568 569 if (mem_props & VK_MEMORY_PROPERTY_CPU_VISIBLE_BIT) { 570 const VK_IMAGE_SUBRESOURCE subres = { 571 .aspect = VK_IMAGE_ASPECT_COLOR, 572 .mipLevel = 0, 573 .arraySlice = 0, 574 }; 575 VK_SUBRESOURCE_LAYOUT layout; 576 size_t layout_size = sizeof(VK_SUBRESOURCE_LAYOUT); 577 void *data; 578 int32_t x, y; 579 580 err = vkGetImageSubresourceInfo(tex_obj->image, &subres, 581 VK_INFO_TYPE_SUBRESOURCE_LAYOUT, 582 &layout_size, &layout); 583 assert(!err && layout_size == sizeof(layout)); 584 /* Linear texture must be within a single memory object */ 585 assert(num_allocations == 1); 586 587 err = vkMapMemory(tex_obj->mem[0], 0, &data); 588 assert(!err); 589 590 for (y = 0; y < tex_height; y++) { 591 uint32_t *row = (uint32_t *) ((char *) data + layout.rowPitch * y); 592 for (x = 0; x < tex_width; x++) 593 row[x] = tex_colors[(x & 1) ^ (y & 1)]; 594 } 595 596 err = vkUnmapMemory(tex_obj->mem[0]); 597 assert(!err); 598 } 599 600 tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 601 demo_set_image_layout(demo, tex_obj->image, 602 VK_IMAGE_LAYOUT_UNDEFINED, 603 tex_obj->imageLayout); 604 /* setting the image layout does not reference the actual memory so no need to add a mem ref */ 605} 606 607static void demo_destroy_texture_image(struct texture_object *tex_obj) 608{ 609 /* clean up staging resources */ 610 for (uint32_t j = 0; j < tex_obj->num_mem; j ++) { 611 vkBindObjectMemory(tex_obj->image, j, VK_NULL_HANDLE, 0); 612 vkFreeMemory(tex_obj->mem[j]); 613 } 614 615 free(tex_obj->mem); 616 vkDestroyObject(tex_obj->image); 617} 618 619static void demo_prepare_textures(struct demo *demo) 620{ 621 const VK_FORMAT tex_format = VK_FMT_B8G8R8A8_UNORM; 622 VK_FORMAT_PROPERTIES props; 623 size_t size = sizeof(props); 624 const uint32_t tex_colors[DEMO_TEXTURE_COUNT][2] = { 625 { 0xffff0000, 0xff00ff00 }, 626 }; 627 VK_RESULT err; 628 uint32_t i; 629 630 err = vkGetFormatInfo(demo->device, tex_format, 631 VK_INFO_TYPE_FORMAT_PROPERTIES, 632 &size, &props); 633 assert(!err); 634 635 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 636 if ((props.linearTilingFeatures & VK_FORMAT_IMAGE_SHADER_READ_BIT) && !demo->use_staging_buffer) { 637 /* Device can texture using linear textures */ 638 demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i], 639 VK_LINEAR_TILING, VK_MEMORY_PROPERTY_CPU_VISIBLE_BIT); 640 } else if (props.optimalTilingFeatures & VK_FORMAT_IMAGE_SHADER_READ_BIT){ 641 /* Must use staging buffer to copy linear texture to optimized */ 642 struct texture_object staging_texture; 643 644 memset(&staging_texture, 0, sizeof(staging_texture)); 645 demo_prepare_texture_image(demo, tex_colors[i], &staging_texture, 646 VK_LINEAR_TILING, VK_MEMORY_PROPERTY_CPU_VISIBLE_BIT); 647 648 demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i], 649 VK_OPTIMAL_TILING, VK_MEMORY_PROPERTY_GPU_ONLY); 650 651 demo_set_image_layout(demo, staging_texture.image, 652 staging_texture.imageLayout, 653 VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL); 654 655 demo_set_image_layout(demo, demo->textures[i].image, 656 demo->textures[i].imageLayout, 657 VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL); 658 659 VK_IMAGE_COPY copy_region = { 660 .srcSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 }, 661 .srcOffset = { 0, 0, 0 }, 662 .destSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 }, 663 .destOffset = { 0, 0, 0 }, 664 .extent = { staging_texture.tex_width, staging_texture.tex_height, 1 }, 665 }; 666 vkCmdCopyImage(demo->cmd, 667 staging_texture.image, VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, 668 demo->textures[i].image, VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, 669 1, ©_region); 670 671 demo_add_mem_refs(demo, staging_texture.num_mem, staging_texture.mem); 672 demo_add_mem_refs(demo, demo->textures[i].num_mem, demo->textures[i].mem); 673 674 demo_set_image_layout(demo, demo->textures[i].image, 675 VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, 676 demo->textures[i].imageLayout); 677 678 demo_flush_init_cmd(demo); 679 680 demo_destroy_texture_image(&staging_texture); 681 demo_remove_mem_refs(demo, staging_texture.num_mem, staging_texture.mem); 682 } else { 683 /* Can't support VK_FMT_B8G8R8A8_UNORM !? */ 684 assert(!"No support for B8G8R8A8_UNORM as texture image format"); 685 } 686 687 const VK_SAMPLER_CREATE_INFO sampler = { 688 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 689 .pNext = NULL, 690 .magFilter = VK_TEX_FILTER_NEAREST, 691 .minFilter = VK_TEX_FILTER_NEAREST, 692 .mipMode = VK_TEX_MIPMAP_BASE, 693 .addressU = VK_TEX_ADDRESS_WRAP, 694 .addressV = VK_TEX_ADDRESS_WRAP, 695 .addressW = VK_TEX_ADDRESS_WRAP, 696 .mipLodBias = 0.0f, 697 .maxAnisotropy = 1, 698 .compareFunc = VK_COMPARE_NEVER, 699 .minLod = 0.0f, 700 .maxLod = 0.0f, 701 .borderColorType = VK_BORDER_COLOR_OPAQUE_WHITE, 702 }; 703 VK_IMAGE_VIEW_CREATE_INFO view = { 704 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 705 .pNext = NULL, 706 .image = VK_NULL_HANDLE, 707 .viewType = VK_IMAGE_VIEW_2D, 708 .format = tex_format, 709 .channels = { VK_CHANNEL_SWIZZLE_R, 710 VK_CHANNEL_SWIZZLE_G, 711 VK_CHANNEL_SWIZZLE_B, 712 VK_CHANNEL_SWIZZLE_A, }, 713 .subresourceRange = { VK_IMAGE_ASPECT_COLOR, 0, 1, 0, 1 }, 714 .minLod = 0.0f, 715 }; 716 717 /* create sampler */ 718 err = vkCreateSampler(demo->device, &sampler, 719 &demo->textures[i].sampler); 720 assert(!err); 721 722 /* create image view */ 723 view.image = demo->textures[i].image; 724 err = vkCreateImageView(demo->device, &view, 725 &demo->textures[i].view); 726 assert(!err); 727 } 728} 729 730static void demo_prepare_vertices(struct demo *demo) 731{ 732 const float vb[3][5] = { 733 /* position texcoord */ 734 { -1.0f, -1.0f, -0.6f, 0.0f, 0.0f }, 735 { 1.0f, -1.0f, -0.5f, 1.0f, 0.0f }, 736 { 0.0f, 1.0f, 1.0f, 0.5f, 1.0f }, 737 }; 738 const VK_BUFFER_CREATE_INFO buf_info = { 739 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 740 .pNext = NULL, 741 .size = sizeof(vb), 742 .usage = VK_BUFFER_USAGE_VERTEX_FETCH_BIT, 743 .flags = 0, 744 }; 745 VK_MEMORY_ALLOC_BUFFER_INFO buf_alloc = { 746 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_BUFFER_INFO, 747 .pNext = NULL, 748 }; 749 VK_MEMORY_ALLOC_INFO mem_alloc = { 750 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, 751 .pNext = &buf_alloc, 752 .allocationSize = 0, 753 .memProps = VK_MEMORY_PROPERTY_CPU_VISIBLE_BIT, 754 .memType = VK_MEMORY_TYPE_BUFFER, 755 .memPriority = VK_MEMORY_PRIORITY_NORMAL, 756 }; 757 VK_MEMORY_REQUIREMENTS *mem_reqs; 758 size_t mem_reqs_size = sizeof(VK_MEMORY_REQUIREMENTS); 759 VK_BUFFER_MEMORY_REQUIREMENTS buf_reqs; 760 size_t buf_reqs_size = sizeof(VK_BUFFER_MEMORY_REQUIREMENTS); 761 uint32_t num_allocations = 0; 762 size_t num_alloc_size = sizeof(num_allocations); 763 VK_RESULT err; 764 void *data; 765 766 memset(&demo->vertices, 0, sizeof(demo->vertices)); 767 768 err = vkCreateBuffer(demo->device, &buf_info, &demo->vertices.buf); 769 assert(!err); 770 771 err = vkGetObjectInfo(demo->vertices.buf, 772 VK_INFO_TYPE_MEMORY_ALLOCATION_COUNT, 773 &num_alloc_size, &num_allocations); 774 assert(!err && num_alloc_size == sizeof(num_allocations)); 775 mem_reqs = malloc(num_allocations * sizeof(VK_MEMORY_REQUIREMENTS)); 776 demo->vertices.mem = malloc(num_allocations * sizeof(VK_GPU_MEMORY)); 777 demo->vertices.num_mem = num_allocations; 778 err = vkGetObjectInfo(demo->vertices.buf, 779 VK_INFO_TYPE_MEMORY_REQUIREMENTS, 780 &mem_reqs_size, mem_reqs); 781 assert(!err && mem_reqs_size == sizeof(*mem_reqs)); 782 err = vkGetObjectInfo(demo->vertices.buf, 783 VK_INFO_TYPE_BUFFER_MEMORY_REQUIREMENTS, 784 &buf_reqs_size, &buf_reqs); 785 assert(!err && buf_reqs_size == sizeof(VK_BUFFER_MEMORY_REQUIREMENTS)); 786 buf_alloc.usage = buf_reqs.usage; 787 for (uint32_t i = 0; i < num_allocations; i ++) { 788 mem_alloc.allocationSize = mem_reqs[i].size; 789 790 err = vkAllocMemory(demo->device, &mem_alloc, &demo->vertices.mem[i]); 791 assert(!err); 792 793 err = vkMapMemory(demo->vertices.mem[i], 0, &data); 794 assert(!err); 795 796 memcpy(data, vb, sizeof(vb)); 797 798 err = vkUnmapMemory(demo->vertices.mem[i]); 799 assert(!err); 800 801 err = vkBindObjectMemory(demo->vertices.buf, i, demo->vertices.mem[i], 0); 802 assert(!err); 803 } 804 805 demo_add_mem_refs(demo, demo->vertices.num_mem, demo->vertices.mem); 806 807 demo->vertices.vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_CREATE_INFO; 808 demo->vertices.vi.pNext = NULL; 809 demo->vertices.vi.bindingCount = 1; 810 demo->vertices.vi.pVertexBindingDescriptions = demo->vertices.vi_bindings; 811 demo->vertices.vi.attributeCount = 2; 812 demo->vertices.vi.pVertexAttributeDescriptions = demo->vertices.vi_attrs; 813 814 demo->vertices.vi_bindings[0].binding = VERTEX_BUFFER_BIND_ID; 815 demo->vertices.vi_bindings[0].strideInBytes = sizeof(vb[0]); 816 demo->vertices.vi_bindings[0].stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX; 817 818 demo->vertices.vi_attrs[0].binding = VERTEX_BUFFER_BIND_ID; 819 demo->vertices.vi_attrs[0].location = 0; 820 demo->vertices.vi_attrs[0].format = VK_FMT_R32G32B32_SFLOAT; 821 demo->vertices.vi_attrs[0].offsetInBytes = 0; 822 823 demo->vertices.vi_attrs[1].binding = VERTEX_BUFFER_BIND_ID; 824 demo->vertices.vi_attrs[1].location = 1; 825 demo->vertices.vi_attrs[1].format = VK_FMT_R32G32_SFLOAT; 826 demo->vertices.vi_attrs[1].offsetInBytes = sizeof(float) * 3; 827} 828 829static void demo_prepare_descriptor_layout(struct demo *demo) 830{ 831 const VK_DESCRIPTOR_SET_LAYOUT_BINDING layout_binding = { 832 .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER_TEXTURE, 833 .count = DEMO_TEXTURE_COUNT, 834 .stageFlags = VK_SHADER_STAGE_FLAGS_FRAGMENT_BIT, 835 .pImmutableSamplers = NULL, 836 }; 837 const VK_DESCRIPTOR_SET_LAYOUT_CREATE_INFO descriptor_layout = { 838 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 839 .pNext = NULL, 840 .count = 1, 841 .pBinding = &layout_binding, 842 }; 843 VK_RESULT err; 844 845 err = vkCreateDescriptorSetLayout(demo->device, 846 &descriptor_layout, &demo->desc_layout); 847 assert(!err); 848 849 err = vkCreateDescriptorSetLayoutChain(demo->device, 850 1, &demo->desc_layout, &demo->desc_layout_chain); 851 assert(!err); 852} 853 854static VK_SHADER demo_prepare_shader(struct demo *demo, 855 VK_PIPELINE_SHADER_STAGE stage, 856 const void *code, 857 size_t size) 858{ 859 VK_SHADER_CREATE_INFO createInfo; 860 VK_SHADER shader; 861 VK_RESULT err; 862 863 createInfo.sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO; 864 createInfo.pNext = NULL; 865 866 // Create fake SPV structure to feed GLSL 867 // to the driver "under the covers" 868 createInfo.codeSize = 3 * sizeof(uint32_t) + size + 1; 869 createInfo.pCode = malloc(createInfo.codeSize); 870 createInfo.flags = 0; 871 872 /* try version 0 first: VK_PIPELINE_SHADER_STAGE followed by GLSL */ 873 ((uint32_t *) createInfo.pCode)[0] = ICD_SPV_MAGIC; 874 ((uint32_t *) createInfo.pCode)[1] = 0; 875 ((uint32_t *) createInfo.pCode)[2] = stage; 876 memcpy(((uint32_t *) createInfo.pCode + 3), code, size + 1); 877 878 err = vkCreateShader(demo->device, &createInfo, &shader); 879 if (err) { 880 free((void *) createInfo.pCode); 881 return NULL; 882 } 883 884 return shader; 885} 886 887static VK_SHADER demo_prepare_vs(struct demo *demo) 888{ 889 static const char *vertShaderText = 890 "#version 140\n" 891 "#extension GL_ARB_separate_shader_objects : enable\n" 892 "#extension GL_ARB_shading_language_420pack : enable\n" 893 "layout (location = 0) in vec4 pos;\n" 894 "layout (location = 1) in vec2 attr;\n" 895 "out vec2 texcoord;\n" 896 "void main() {\n" 897 " texcoord = attr;\n" 898 " gl_Position = pos;\n" 899 "}\n"; 900 901 return demo_prepare_shader(demo, VK_SHADER_STAGE_VERTEX, 902 (const void *) vertShaderText, 903 strlen(vertShaderText)); 904} 905 906static VK_SHADER demo_prepare_fs(struct demo *demo) 907{ 908 static const char *fragShaderText = 909 "#version 140\n" 910 "#extension GL_ARB_separate_shader_objects : enable\n" 911 "#extension GL_ARB_shading_language_420pack : enable\n" 912 "layout (binding = 0) uniform sampler2D tex;\n" 913 "layout (location = 0) in vec2 texcoord;\n" 914 "void main() {\n" 915 " gl_FragColor = texture(tex, texcoord);\n" 916 "}\n"; 917 918 return demo_prepare_shader(demo, VK_SHADER_STAGE_FRAGMENT, 919 (const void *) fragShaderText, 920 strlen(fragShaderText)); 921} 922 923static void demo_prepare_pipeline(struct demo *demo) 924{ 925 VK_GRAPHICS_PIPELINE_CREATE_INFO pipeline; 926 VK_PIPELINE_VERTEX_INPUT_CREATE_INFO vi; 927 VK_PIPELINE_IA_STATE_CREATE_INFO ia; 928 VK_PIPELINE_RS_STATE_CREATE_INFO rs; 929 VK_PIPELINE_CB_STATE_CREATE_INFO cb; 930 VK_PIPELINE_DS_STATE_CREATE_INFO ds; 931 VK_PIPELINE_SHADER_STAGE_CREATE_INFO vs; 932 VK_PIPELINE_SHADER_STAGE_CREATE_INFO fs; 933 VK_PIPELINE_VP_STATE_CREATE_INFO vp; 934 VK_PIPELINE_MS_STATE_CREATE_INFO ms; 935 VK_RESULT err; 936 937 memset(&pipeline, 0, sizeof(pipeline)); 938 pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 939 pipeline.pSetLayoutChain = demo->desc_layout_chain; 940 941 vi = demo->vertices.vi; 942 943 memset(&ia, 0, sizeof(ia)); 944 ia.sType = VK_STRUCTURE_TYPE_PIPELINE_IA_STATE_CREATE_INFO; 945 ia.topology = VK_TOPOLOGY_TRIANGLE_LIST; 946 947 memset(&rs, 0, sizeof(rs)); 948 rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RS_STATE_CREATE_INFO; 949 rs.fillMode = VK_FILL_SOLID; 950 rs.cullMode = VK_CULL_NONE; 951 rs.frontFace = VK_FRONT_FACE_CCW; 952 953 memset(&cb, 0, sizeof(cb)); 954 cb.sType = VK_STRUCTURE_TYPE_PIPELINE_CB_STATE_CREATE_INFO; 955 VK_PIPELINE_CB_ATTACHMENT_STATE att_state[1]; 956 memset(att_state, 0, sizeof(att_state)); 957 att_state[0].format = demo->format; 958 att_state[0].channelWriteMask = 0xf; 959 att_state[0].blendEnable = VK_FALSE; 960 cb.attachmentCount = 1; 961 cb.pAttachments = att_state; 962 963 964 memset(&vp, 0, sizeof(vp)); 965 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VP_STATE_CREATE_INFO; 966 vp.numViewports = 1; 967 vp.clipOrigin = VK_COORDINATE_ORIGIN_UPPER_LEFT; 968 969 memset(&ds, 0, sizeof(ds)); 970 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DS_STATE_CREATE_INFO; 971 ds.format = demo->depth.format; 972 ds.depthTestEnable = VK_TRUE; 973 ds.depthWriteEnable = VK_TRUE; 974 ds.depthFunc = VK_COMPARE_LESS_EQUAL; 975 ds.depthBoundsEnable = VK_FALSE; 976 ds.back.stencilFailOp = VK_STENCIL_OP_KEEP; 977 ds.back.stencilPassOp = VK_STENCIL_OP_KEEP; 978 ds.back.stencilFunc = VK_COMPARE_ALWAYS; 979 ds.stencilTestEnable = VK_FALSE; 980 ds.front = ds.back; 981 982 memset(&vs, 0, sizeof(vs)); 983 vs.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 984 vs.shader.stage = VK_SHADER_STAGE_VERTEX; 985 vs.shader.shader = demo_prepare_vs(demo); 986 vs.shader.linkConstBufferCount = 0; 987 988 memset(&fs, 0, sizeof(fs)); 989 fs.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 990 fs.shader.stage = VK_SHADER_STAGE_FRAGMENT; 991 fs.shader.shader = demo_prepare_fs(demo); 992 993 memset(&ms, 0, sizeof(ms)); 994 ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MS_STATE_CREATE_INFO; 995 ms.sampleMask = 1; 996 ms.multisampleEnable = VK_FALSE; 997 ms.samples = 1; 998 999 pipeline.pNext = (const void *) &vi; 1000 vi.pNext = (void *) &ia; 1001 ia.pNext = (const void *) &rs; 1002 rs.pNext = (const void *) &cb; 1003 cb.pNext = (const void *) &ms; 1004 ms.pNext = (const void *) &vp; 1005 vp.pNext = (const void *) &ds; 1006 ds.pNext = (const void *) &vs; 1007 vs.pNext = (const void *) &fs; 1008 1009 err = vkCreateGraphicsPipeline(demo->device, &pipeline, &demo->pipeline); 1010 assert(!err); 1011 1012 vkDestroyObject(vs.shader.shader); 1013 vkDestroyObject(fs.shader.shader); 1014} 1015 1016static void demo_prepare_dynamic_states(struct demo *demo) 1017{ 1018 VK_DYNAMIC_VP_STATE_CREATE_INFO viewport_create; 1019 VK_DYNAMIC_RS_STATE_CREATE_INFO raster; 1020 VK_DYNAMIC_CB_STATE_CREATE_INFO color_blend; 1021 VK_DYNAMIC_DS_STATE_CREATE_INFO depth_stencil; 1022 VK_RESULT err; 1023 1024 memset(&viewport_create, 0, sizeof(viewport_create)); 1025 viewport_create.sType = VK_STRUCTURE_TYPE_DYNAMIC_VP_STATE_CREATE_INFO; 1026 viewport_create.viewportAndScissorCount = 1; 1027 VK_VIEWPORT viewport; 1028 memset(&viewport, 0, sizeof(viewport)); 1029 viewport.height = (float) demo->height; 1030 viewport.width = (float) demo->width; 1031 viewport.minDepth = (float) 0.0f; 1032 viewport.maxDepth = (float) 1.0f; 1033 viewport_create.pViewports = &viewport; 1034 VK_RECT scissor; 1035 memset(&scissor, 0, sizeof(scissor)); 1036 scissor.extent.width = demo->width; 1037 scissor.extent.height = demo->height; 1038 scissor.offset.x = 0; 1039 scissor.offset.y = 0; 1040 viewport_create.pScissors = &scissor; 1041 1042 memset(&raster, 0, sizeof(raster)); 1043 raster.sType = VK_STRUCTURE_TYPE_DYNAMIC_RS_STATE_CREATE_INFO; 1044 raster.pointSize = 1.0; 1045 raster.lineWidth = 1.0; 1046 1047 memset(&color_blend, 0, sizeof(color_blend)); 1048 color_blend.sType = VK_STRUCTURE_TYPE_DYNAMIC_CB_STATE_CREATE_INFO; 1049 color_blend.blendConst[0] = 1.0f; 1050 color_blend.blendConst[1] = 1.0f; 1051 color_blend.blendConst[2] = 1.0f; 1052 color_blend.blendConst[3] = 1.0f; 1053 1054 memset(&depth_stencil, 0, sizeof(depth_stencil)); 1055 depth_stencil.sType = VK_STRUCTURE_TYPE_DYNAMIC_DS_STATE_CREATE_INFO; 1056 depth_stencil.minDepth = 0.0f; 1057 depth_stencil.maxDepth = 1.0f; 1058 depth_stencil.stencilBackRef = 0; 1059 depth_stencil.stencilFrontRef = 0; 1060 depth_stencil.stencilReadMask = 0xff; 1061 depth_stencil.stencilWriteMask = 0xff; 1062 1063 err = vkCreateDynamicViewportState(demo->device, &viewport_create, &demo->viewport); 1064 assert(!err); 1065 1066 err = vkCreateDynamicRasterState(demo->device, &raster, &demo->raster); 1067 assert(!err); 1068 1069 err = vkCreateDynamicColorBlendState(demo->device, 1070 &color_blend, &demo->color_blend); 1071 assert(!err); 1072 1073 err = vkCreateDynamicDepthStencilState(demo->device, 1074 &depth_stencil, &demo->depth_stencil); 1075 assert(!err); 1076} 1077 1078static void demo_prepare_descriptor_pool(struct demo *demo) 1079{ 1080 const VK_DESCRIPTOR_TYPE_COUNT type_count = { 1081 .type = VK_DESCRIPTOR_TYPE_SAMPLER_TEXTURE, 1082 .count = DEMO_TEXTURE_COUNT, 1083 }; 1084 const VK_DESCRIPTOR_POOL_CREATE_INFO descriptor_pool = { 1085 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 1086 .pNext = NULL, 1087 .count = 1, 1088 .pTypeCount = &type_count, 1089 }; 1090 VK_RESULT err; 1091 1092 err = vkCreateDescriptorPool(demo->device, 1093 VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1, 1094 &descriptor_pool, &demo->desc_pool); 1095 assert(!err); 1096} 1097 1098static void demo_prepare_descriptor_set(struct demo *demo) 1099{ 1100 VK_IMAGE_VIEW_ATTACH_INFO view_info[DEMO_TEXTURE_COUNT]; 1101 VK_SAMPLER_IMAGE_VIEW_INFO combined_info[DEMO_TEXTURE_COUNT]; 1102 VK_UPDATE_SAMPLER_TEXTURES update; 1103 const void *update_array[1] = { &update }; 1104 VK_RESULT err; 1105 uint32_t count; 1106 uint32_t i; 1107 1108 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1109 view_info[i].sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_ATTACH_INFO; 1110 view_info[i].pNext = NULL; 1111 view_info[i].view = demo->textures[i].view, 1112 view_info[i].layout = VK_IMAGE_LAYOUT_GENERAL; 1113 1114 combined_info[i].sampler = demo->textures[i].sampler; 1115 combined_info[i].pImageView = &view_info[i]; 1116 } 1117 1118 memset(&update, 0, sizeof(update)); 1119 update.sType = VK_STRUCTURE_TYPE_UPDATE_SAMPLER_TEXTURES; 1120 update.count = DEMO_TEXTURE_COUNT; 1121 update.pSamplerImageViews = combined_info; 1122 1123 err = vkAllocDescriptorSets(demo->desc_pool, 1124 VK_DESCRIPTOR_SET_USAGE_STATIC, 1125 1, &demo->desc_layout, 1126 &demo->desc_set, &count); 1127 assert(!err && count == 1); 1128 1129 vkBeginDescriptorPoolUpdate(demo->device, 1130 VK_DESCRIPTOR_UPDATE_MODE_FASTEST); 1131 1132 vkClearDescriptorSets(demo->desc_pool, 1, &demo->desc_set); 1133 vkUpdateDescriptors(demo->desc_set, 1, update_array); 1134 1135 vkEndDescriptorPoolUpdate(demo->device, demo->cmd); 1136} 1137 1138static void demo_prepare(struct demo *demo) 1139{ 1140 const VK_CMD_BUFFER_CREATE_INFO cmd = { 1141 .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO, 1142 .pNext = NULL, 1143 .queueNodeIndex = demo->graphics_queue_node_index, 1144 .flags = 0, 1145 }; 1146 VK_RESULT err; 1147 1148 demo_prepare_buffers(demo); 1149 demo_prepare_depth(demo); 1150 demo_prepare_textures(demo); 1151 demo_prepare_vertices(demo); 1152 demo_prepare_descriptor_layout(demo); 1153 demo_prepare_pipeline(demo); 1154 demo_prepare_dynamic_states(demo); 1155 1156 err = vkCreateCommandBuffer(demo->device, &cmd, &demo->cmd); 1157 assert(!err); 1158 1159 demo_prepare_descriptor_pool(demo); 1160 demo_prepare_descriptor_set(demo); 1161} 1162 1163static void demo_handle_event(struct demo *demo, 1164 const xcb_generic_event_t *event) 1165{ 1166 switch (event->response_type & 0x7f) { 1167 case XCB_EXPOSE: 1168 demo_draw(demo); 1169 break; 1170 case XCB_CLIENT_MESSAGE: 1171 if((*(xcb_client_message_event_t*)event).data.data32[0] == 1172 (*demo->atom_wm_delete_window).atom) { 1173 demo->quit = true; 1174 } 1175 break; 1176 case XCB_KEY_RELEASE: 1177 { 1178 const xcb_key_release_event_t *key = 1179 (const xcb_key_release_event_t *) event; 1180 1181 if (key->detail == 0x9) 1182 demo->quit = true; 1183 } 1184 break; 1185 case XCB_DESTROY_NOTIFY: 1186 demo->quit = true; 1187 break; 1188 default: 1189 break; 1190 } 1191} 1192 1193static void demo_run(struct demo *demo) 1194{ 1195 xcb_flush(demo->connection); 1196 1197 while (!demo->quit) { 1198 xcb_generic_event_t *event; 1199 1200 event = xcb_wait_for_event(demo->connection); 1201 if (event) { 1202 demo_handle_event(demo, event); 1203 free(event); 1204 } 1205 } 1206} 1207 1208static void demo_create_window(struct demo *demo) 1209{ 1210 uint32_t value_mask, value_list[32]; 1211 1212 demo->window = xcb_generate_id(demo->connection); 1213 1214 value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 1215 value_list[0] = demo->screen->black_pixel; 1216 value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | 1217 XCB_EVENT_MASK_EXPOSURE | 1218 XCB_EVENT_MASK_STRUCTURE_NOTIFY; 1219 1220 xcb_create_window(demo->connection, 1221 XCB_COPY_FROM_PARENT, 1222 demo->window, demo->screen->root, 1223 0, 0, demo->width, demo->height, 0, 1224 XCB_WINDOW_CLASS_INPUT_OUTPUT, 1225 demo->screen->root_visual, 1226 value_mask, value_list); 1227 1228 /* Magic code that will send notification when window is destroyed */ 1229 xcb_intern_atom_cookie_t cookie = xcb_intern_atom(demo->connection, 1, 12, 1230 "WM_PROTOCOLS"); 1231 xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(demo->connection, cookie, 0); 1232 1233 xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW"); 1234 demo->atom_wm_delete_window = xcb_intern_atom_reply(demo->connection, cookie2, 0); 1235 1236 xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, 1237 demo->window, (*reply).atom, 4, 32, 1, 1238 &(*demo->atom_wm_delete_window).atom); 1239 free(reply); 1240 1241 xcb_map_window(demo->connection, demo->window); 1242} 1243 1244static void demo_init_vk(struct demo *demo) 1245{ 1246 const VK_APPLICATION_INFO app = { 1247 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 1248 .pNext = NULL, 1249 .pAppName = "tri", 1250 .appVersion = 0, 1251 .pEngineName = "tri", 1252 .engineVersion = 0, 1253 .apiVersion = VK_API_VERSION, 1254 }; 1255 const VK_INSTANCE_CREATE_INFO inst_info = { 1256 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 1257 .pNext = NULL, 1258 .pAppInfo = &app, 1259 .pAllocCb = NULL, 1260 .extensionCount = 0, 1261 .ppEnabledExtensionNames = NULL, 1262 }; 1263 const VK_WSI_X11_CONNECTION_INFO connection = { 1264 .pConnection = demo->connection, 1265 .root = demo->screen->root, 1266 .provider = 0, 1267 }; 1268 const VK_DEVICE_QUEUE_CREATE_INFO queue = { 1269 .queueNodeIndex = 0, 1270 .queueCount = 1, 1271 }; 1272 const char *ext_names[] = { 1273 "VK_WSI_X11", 1274 }; 1275 const VK_DEVICE_CREATE_INFO device = { 1276 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 1277 .pNext = NULL, 1278 .queueRecordCount = 1, 1279 .pRequestedQueues = &queue, 1280 .extensionCount = 1, 1281 .ppEnabledExtensionNames = ext_names, 1282 .maxValidationLevel = VK_VALIDATION_LEVEL_END_RANGE, 1283 .flags = VK_DEVICE_CREATE_VALIDATION_BIT, 1284 }; 1285 VK_RESULT err; 1286 uint32_t gpu_count; 1287 uint32_t i; 1288 size_t data_size; 1289 uint32_t queue_count; 1290 1291 err = vkCreateInstance(&inst_info, &demo->inst); 1292 if (err == VK_ERROR_INCOMPATIBLE_DRIVER) { 1293 printf("Cannot find a compatible Vulkan installable client driver " 1294 "(ICD).\nExiting ...\n"); 1295 fflush(stdout); 1296 exit(1); 1297 } else { 1298 assert(!err); 1299 } 1300 1301 err = vkEnumerateGpus(demo->inst, 1, &gpu_count, &demo->gpu); 1302 assert(!err && gpu_count == 1); 1303 1304 for (i = 0; i < device.extensionCount; i++) { 1305 err = vkGetExtensionSupport(demo->gpu, ext_names[i]); 1306 assert(!err); 1307 } 1308 1309 err = vkWsiX11AssociateConnection(demo->gpu, &connection); 1310 assert(!err); 1311 1312 err = vkCreateDevice(demo->gpu, &device, &demo->device); 1313 assert(!err); 1314 1315 err = vkGetGpuInfo(demo->gpu, VK_INFO_TYPE_PHYSICAL_GPU_PROPERTIES, 1316 &data_size, NULL); 1317 assert(!err); 1318 1319 demo->gpu_props = (VK_PHYSICAL_GPU_PROPERTIES *) malloc(data_size); 1320 err = vkGetGpuInfo(demo->gpu, VK_INFO_TYPE_PHYSICAL_GPU_PROPERTIES, 1321 &data_size, demo->gpu_props); 1322 assert(!err); 1323 1324 err = vkGetGpuInfo(demo->gpu, VK_INFO_TYPE_PHYSICAL_GPU_QUEUE_PROPERTIES, 1325 &data_size, NULL); 1326 assert(!err); 1327 1328 demo->queue_props = (VK_PHYSICAL_GPU_QUEUE_PROPERTIES *) malloc(data_size); 1329 err = vkGetGpuInfo(demo->gpu, VK_INFO_TYPE_PHYSICAL_GPU_QUEUE_PROPERTIES, 1330 &data_size, demo->queue_props); 1331 assert(!err); 1332 queue_count = (uint32_t) (data_size / sizeof(VK_PHYSICAL_GPU_QUEUE_PROPERTIES)); 1333 assert(queue_count >= 1); 1334 1335 for (i = 0; i < queue_count; i++) { 1336 if (demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) 1337 break; 1338 } 1339 assert(i < queue_count); 1340 demo->graphics_queue_node_index = i; 1341 1342 err = vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 1343 0, &demo->queue); 1344 assert(!err); 1345} 1346 1347static void demo_init_connection(struct demo *demo) 1348{ 1349 const xcb_setup_t *setup; 1350 xcb_screen_iterator_t iter; 1351 int scr; 1352 1353 demo->connection = xcb_connect(NULL, &scr); 1354 if (demo->connection == NULL) { 1355 printf("Cannot find a compatible Vulkan installable client driver " 1356 "(ICD).\nExiting ...\n"); 1357 fflush(stdout); 1358 exit(1); 1359 } 1360 1361 setup = xcb_get_setup(demo->connection); 1362 iter = xcb_setup_roots_iterator(setup); 1363 while (scr-- > 0) 1364 xcb_screen_next(&iter); 1365 1366 demo->screen = iter.data; 1367} 1368 1369static void demo_init(struct demo *demo, const int argc, const char *argv[]) 1370{ 1371 memset(demo, 0, sizeof(*demo)); 1372 1373 for (int i = 0; i < argc; i++) { 1374 if (strncmp(argv[i], "--use_staging", strlen("--use_staging")) == 0) 1375 demo->use_staging_buffer = true; 1376 } 1377 1378 demo_init_connection(demo); 1379 demo_init_vk(demo); 1380 1381 demo->width = 300; 1382 demo->height = 300; 1383 demo->format = VK_FMT_B8G8R8A8_UNORM; 1384} 1385 1386static void demo_cleanup(struct demo *demo) 1387{ 1388 uint32_t i, j; 1389 1390 vkDestroyObject(demo->desc_set); 1391 vkDestroyObject(demo->desc_pool); 1392 1393 vkDestroyObject(demo->cmd); 1394 1395 vkDestroyObject(demo->viewport); 1396 vkDestroyObject(demo->raster); 1397 vkDestroyObject(demo->color_blend); 1398 vkDestroyObject(demo->depth_stencil); 1399 1400 vkDestroyObject(demo->pipeline); 1401 vkDestroyObject(demo->desc_layout_chain); 1402 vkDestroyObject(demo->desc_layout); 1403 1404 vkBindObjectMemory(demo->vertices.buf, 0, VK_NULL_HANDLE, 0); 1405 vkDestroyObject(demo->vertices.buf); 1406 demo_remove_mem_refs(demo, demo->vertices.num_mem, demo->vertices.mem); 1407 for (j = 0; j < demo->vertices.num_mem; j++) 1408 vkFreeMemory(demo->vertices.mem[j]); 1409 1410 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) { 1411 vkDestroyObject(demo->textures[i].view); 1412 vkBindObjectMemory(demo->textures[i].image, 0, VK_NULL_HANDLE, 0); 1413 vkDestroyObject(demo->textures[i].image); 1414 demo_remove_mem_refs(demo, demo->textures[i].num_mem, demo->textures[i].mem); 1415 for (j = 0; j < demo->textures[i].num_mem; j++) 1416 vkFreeMemory(demo->textures[i].mem[j]); 1417 free(demo->textures[i].mem); 1418 vkDestroyObject(demo->textures[i].sampler); 1419 } 1420 1421 vkDestroyObject(demo->depth.view); 1422 vkBindObjectMemory(demo->depth.image, 0, VK_NULL_HANDLE, 0); 1423 demo_remove_mem_refs(demo, demo->depth.num_mem, demo->depth.mem); 1424 vkDestroyObject(demo->depth.image); 1425 for (j = 0; j < demo->depth.num_mem; j++) 1426 vkFreeMemory(demo->depth.mem[j]); 1427 1428 for (i = 0; i < DEMO_BUFFER_COUNT; i++) { 1429 vkDestroyObject(demo->buffers[i].fence); 1430 vkDestroyObject(demo->buffers[i].view); 1431 vkDestroyObject(demo->buffers[i].image); 1432 demo_remove_mem_refs(demo, 1, &demo->buffers[i].mem); 1433 } 1434 1435 vkDestroyDevice(demo->device); 1436 vkDestroyInstance(demo->inst); 1437 1438 xcb_destroy_window(demo->connection, demo->window); 1439 xcb_disconnect(demo->connection); 1440} 1441 1442int main(const int argc, const char *argv[]) 1443{ 1444 struct demo demo; 1445 1446 demo_init(&demo, argc, argv); 1447 1448 demo_prepare(&demo); 1449 demo_create_window(&demo); 1450 demo_run(&demo); 1451 1452 demo_cleanup(&demo); 1453 1454 return 0; 1455} 1456