2 * Copyright (c) 2015-2016 The Khronos Group Inc.
3 * Copyright (c) 2015-2016 Valve Corporation
4 * Copyright (c) 2015-2016 LunarG, Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and/or associated documentation files (the "Materials"), to
8 * deal in the Materials without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Materials, and to permit persons to whom the Materials are
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice(s) and this permission notice shall be included in
14 * all copies or substantial portions of the Materials.
16 * THE MATERIALS ARE 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.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23 * USE OR OTHER DEALINGS IN THE MATERIALS.
25 * Author: Chia-I Wu <olvaffe@gmail.com>
26 * Author: Cody Northrop <cody@lunarg.com>
27 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
28 * Author: Ian Elliott <ian@LunarG.com>
29 * Author: Jon Ashburn <jon@lunarg.com>
30 * Author: Piers Daniell <pdaniell@nvidia.com>
33 * Draw a textured triangle with depth testing. This is written against Intel
34 * ICD. It does not do state transition nor object memory binding like it
35 * should. It also does no error checking.
39 #define _ISOC11_SOURCE /* for aligned_alloc() */
52 #pragma comment(linker, "/subsystem:windows")
53 #define APP_NAME_STR_LEN 80
56 #include <vulkan/vulkan.h>
58 #define DEMO_TEXTURE_COUNT 1
59 #define VERTEX_BUFFER_BIND_ID 0
60 #define APP_SHORT_NAME "tri"
61 #define APP_LONG_NAME "The Vulkan Triangle Demo Program"
63 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
65 #if defined(NDEBUG) && defined(__GNUC__)
66 #define U_ASSERT_ONLY __attribute__((unused))
72 #define ERR_EXIT(err_msg, err_class) \
74 MessageBox(NULL, err_msg, err_class, MB_OK); \
79 #define ERR_EXIT(err_msg, err_class) \
87 #define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
89 demo->fp##entrypoint = \
90 (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \
91 if (demo->fp##entrypoint == NULL) { \
92 ERR_EXIT("vkGetInstanceProcAddr failed to find vk" #entrypoint, \
93 "vkGetInstanceProcAddr Failure"); \
97 #define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
99 demo->fp##entrypoint = \
100 (PFN_vk##entrypoint)vkGetDeviceProcAddr(dev, "vk" #entrypoint); \
101 if (demo->fp##entrypoint == NULL) { \
102 ERR_EXIT("vkGetDeviceProcAddr failed to find vk" #entrypoint, \
103 "vkGetDeviceProcAddr Failure"); \
107 struct texture_object {
111 VkImageLayout imageLayout;
115 int32_t tex_width, tex_height;
118 static int validation_error = 0;
120 VKAPI_ATTR VkBool32 VKAPI_CALL
121 dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
122 uint64_t srcObject, size_t location, int32_t msgCode,
123 const char *pLayerPrefix, const char *pMsg, void *pUserData) {
124 char *message = (char *)malloc(strlen(pMsg) + 100);
128 validation_error = 1;
130 if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
131 sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode,
133 } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
134 sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode,
141 MessageBox(NULL, message, "Alert", MB_OK);
143 printf("%s\n", message);
149 * false indicates that layer should not bail-out of an
150 * API call that had validation failures. This may mean that the
151 * app dies inside the driver due to invalid parameter(s).
152 * That's what would happen without validation layers, so we'll
153 * keep that behavior here.
158 VKAPI_ATTR VkBool32 VKAPI_CALL
159 BreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
160 uint64_t srcObject, size_t location, int32_t msgCode,
161 const char *pLayerPrefix, const char *pMsg,
172 typedef struct _SwapchainBuffers {
180 #define APP_NAME_STR_LEN 80
181 HINSTANCE connection; // hInstance - Windows Instance
182 char name[APP_NAME_STR_LEN]; // Name to put on the window/icon
183 HWND window; // hWnd - window handle
185 struct wl_display *display;
186 struct wl_registry *registry;
187 struct wl_compositor *compositor;
188 struct wl_seat *seat;
189 struct wl_surface *wl_surface;
191 struct wl_shell *shell;
192 struct wl_shell_surface *shell_surface;
194 VkSurfaceKHR surface;
196 bool use_staging_buffer;
199 VkPhysicalDevice gpu;
202 VkPhysicalDeviceProperties gpu_props;
203 VkQueueFamilyProperties *queue_props;
204 uint32_t graphics_queue_node_index;
206 uint32_t enabled_extension_count;
207 uint32_t enabled_layer_count;
208 char *extension_names[64];
209 char *device_validation_layers[64];
213 VkColorSpaceKHR color_space;
215 PFN_vkGetPhysicalDeviceSurfaceSupportKHR
216 fpGetPhysicalDeviceSurfaceSupportKHR;
217 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
218 fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
219 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR
220 fpGetPhysicalDeviceSurfaceFormatsKHR;
221 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR
222 fpGetPhysicalDeviceSurfacePresentModesKHR;
223 PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
224 PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
225 PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
226 PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
227 PFN_vkQueuePresentKHR fpQueuePresentKHR;
228 uint32_t swapchainImageCount;
229 VkSwapchainKHR swapchain;
230 SwapchainBuffers *buffers;
232 VkCommandPool cmd_pool;
242 struct texture_object textures[DEMO_TEXTURE_COUNT];
248 VkPipelineVertexInputStateCreateInfo vi;
249 VkVertexInputBindingDescription vi_bindings[1];
250 VkVertexInputAttributeDescription vi_attrs[2];
253 VkCommandBuffer setup_cmd; // Command Buffer for initialization commands
254 VkCommandBuffer draw_cmd; // Command Buffer for drawing commands
255 VkPipelineLayout pipeline_layout;
256 VkDescriptorSetLayout desc_layout;
257 VkPipelineCache pipelineCache;
258 VkRenderPass render_pass;
261 VkShaderModule vert_shader_module;
262 VkShaderModule frag_shader_module;
264 VkDescriptorPool desc_pool;
265 VkDescriptorSet desc_set;
267 VkFramebuffer *framebuffers;
269 VkPhysicalDeviceMemoryProperties memory_properties;
275 PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback;
276 PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback;
277 VkDebugReportCallbackEXT msg_callback;
278 PFN_vkDebugReportMessageEXT DebugReportMessage;
281 float depthIncrement;
284 uint32_t current_buffer;
285 uint32_t queue_count;
288 // Forward declaration:
289 static void demo_resize(struct demo *demo);
291 static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits,
292 VkFlags requirements_mask,
293 uint32_t *typeIndex) {
296 // Search memtypes to find first index with those properties
297 for (i = 0; i < 32; i++) {
298 if ((typeBits & 1) == 1) {
299 // Type is available, does it match user properties?
300 if ((demo->memory_properties.memoryTypes[i].propertyFlags &
301 requirements_mask) == requirements_mask) {
308 // No memory types matched, return failure
312 static void demo_flush_init_cmd(struct demo *demo) {
313 VkResult U_ASSERT_ONLY err;
315 if (demo->setup_cmd == VK_NULL_HANDLE)
318 err = vkEndCommandBuffer(demo->setup_cmd);
321 const VkCommandBuffer cmd_bufs[] = {demo->setup_cmd};
322 VkFence nullFence = {VK_NULL_HANDLE};
323 VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
325 .waitSemaphoreCount = 0,
326 .pWaitSemaphores = NULL,
327 .pWaitDstStageMask = NULL,
328 .commandBufferCount = 1,
329 .pCommandBuffers = cmd_bufs,
330 .signalSemaphoreCount = 0,
331 .pSignalSemaphores = NULL};
333 err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence);
336 err = vkQueueWaitIdle(demo->queue);
339 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, cmd_bufs);
340 demo->setup_cmd = VK_NULL_HANDLE;
343 static void demo_set_image_layout(struct demo *demo, VkImage image,
344 VkImageAspectFlags aspectMask,
345 VkImageLayout old_image_layout,
346 VkImageLayout new_image_layout,
347 VkAccessFlagBits srcAccessMask) {
349 VkResult U_ASSERT_ONLY err;
351 if (demo->setup_cmd == VK_NULL_HANDLE) {
352 const VkCommandBufferAllocateInfo cmd = {
353 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
355 .commandPool = demo->cmd_pool,
356 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
357 .commandBufferCount = 1,
360 err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->setup_cmd);
363 VkCommandBufferInheritanceInfo cmd_buf_hinfo = {
364 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
366 .renderPass = VK_NULL_HANDLE,
368 .framebuffer = VK_NULL_HANDLE,
369 .occlusionQueryEnable = VK_FALSE,
371 .pipelineStatistics = 0,
373 VkCommandBufferBeginInfo cmd_buf_info = {
374 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
377 .pInheritanceInfo = &cmd_buf_hinfo,
379 err = vkBeginCommandBuffer(demo->setup_cmd, &cmd_buf_info);
383 VkImageMemoryBarrier image_memory_barrier = {
384 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
386 .srcAccessMask = srcAccessMask,
388 .oldLayout = old_image_layout,
389 .newLayout = new_image_layout,
391 .subresourceRange = {aspectMask, 0, 1, 0, 1}};
393 if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
394 /* Make sure anything that was copying from this image has completed */
395 image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
398 if (new_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
399 image_memory_barrier.dstAccessMask =
400 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
403 if (new_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
404 image_memory_barrier.dstAccessMask =
405 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
408 if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
409 /* Make sure any Copy or CPU writes to image are flushed */
410 image_memory_barrier.dstAccessMask =
411 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
414 VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier;
416 VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
417 VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
419 vkCmdPipelineBarrier(demo->setup_cmd, src_stages, dest_stages, 0, 0, NULL,
420 0, NULL, 1, pmemory_barrier);
423 static void demo_draw_build_cmd(struct demo *demo) {
424 const VkCommandBufferInheritanceInfo cmd_buf_hinfo = {
425 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
427 .renderPass = VK_NULL_HANDLE,
429 .framebuffer = VK_NULL_HANDLE,
430 .occlusionQueryEnable = VK_FALSE,
432 .pipelineStatistics = 0,
434 const VkCommandBufferBeginInfo cmd_buf_info = {
435 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
438 .pInheritanceInfo = &cmd_buf_hinfo,
440 const VkClearValue clear_values[2] = {
441 [0] = {.color.float32 = {0.2f, 0.2f, 0.2f, 0.2f}},
442 [1] = {.depthStencil = {demo->depthStencil, 0}},
444 const VkRenderPassBeginInfo rp_begin = {
445 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
447 .renderPass = demo->render_pass,
448 .framebuffer = demo->framebuffers[demo->current_buffer],
449 .renderArea.offset.x = 0,
450 .renderArea.offset.y = 0,
451 .renderArea.extent.width = demo->width,
452 .renderArea.extent.height = demo->height,
453 .clearValueCount = 2,
454 .pClearValues = clear_values,
456 VkResult U_ASSERT_ONLY err;
458 err = vkBeginCommandBuffer(demo->draw_cmd, &cmd_buf_info);
461 vkCmdBeginRenderPass(demo->draw_cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
462 vkCmdBindPipeline(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
464 vkCmdBindDescriptorSets(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
465 demo->pipeline_layout, 0, 1, &demo->desc_set, 0,
469 memset(&viewport, 0, sizeof(viewport));
470 viewport.height = (float)demo->height;
471 viewport.width = (float)demo->width;
472 viewport.minDepth = (float)0.0f;
473 viewport.maxDepth = (float)1.0f;
474 vkCmdSetViewport(demo->draw_cmd, 0, 1, &viewport);
477 memset(&scissor, 0, sizeof(scissor));
478 scissor.extent.width = demo->width;
479 scissor.extent.height = demo->height;
480 scissor.offset.x = 0;
481 scissor.offset.y = 0;
482 vkCmdSetScissor(demo->draw_cmd, 0, 1, &scissor);
484 VkDeviceSize offsets[1] = {0};
485 vkCmdBindVertexBuffers(demo->draw_cmd, VERTEX_BUFFER_BIND_ID, 1,
486 &demo->vertices.buf, offsets);
488 vkCmdDraw(demo->draw_cmd, 3, 1, 0, 0);
489 vkCmdEndRenderPass(demo->draw_cmd);
491 VkImageMemoryBarrier prePresentBarrier = {
492 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
494 .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
495 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
496 .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
497 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
498 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
499 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
500 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
502 prePresentBarrier.image = demo->buffers[demo->current_buffer].image;
503 VkImageMemoryBarrier *pmemory_barrier = &prePresentBarrier;
504 vkCmdPipelineBarrier(demo->draw_cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
505 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0,
506 NULL, 1, pmemory_barrier);
508 err = vkEndCommandBuffer(demo->draw_cmd);
512 static void demo_draw(struct demo *demo) {
513 VkResult U_ASSERT_ONLY err;
514 VkSemaphore presentCompleteSemaphore;
515 VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = {
516 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
521 err = vkCreateSemaphore(demo->device, &presentCompleteSemaphoreCreateInfo,
522 NULL, &presentCompleteSemaphore);
525 // Get the index of the next available swapchain image:
526 err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX,
527 presentCompleteSemaphore,
528 (VkFence)0, // TODO: Show use of fence
529 &demo->current_buffer);
530 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
531 // demo->swapchain is out of date (e.g. the window was resized) and
532 // must be recreated:
535 vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL);
537 } else if (err == VK_SUBOPTIMAL_KHR) {
538 // demo->swapchain is not as optimal as it could be, but the platform's
539 // presentation engine will still present the image correctly.
544 // Assume the command buffer has been run on current_buffer before so
545 // we need to set the image layout back to COLOR_ATTACHMENT_OPTIMAL
546 demo_set_image_layout(demo, demo->buffers[demo->current_buffer].image,
547 VK_IMAGE_ASPECT_COLOR_BIT,
548 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
549 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
551 demo_flush_init_cmd(demo);
553 // Wait for the present complete semaphore to be signaled to ensure
554 // that the image won't be rendered to until the presentation
555 // engine has fully released ownership to the application, and it is
556 // okay to render to the image.
558 // FIXME/TODO: DEAL WITH VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
559 demo_draw_build_cmd(demo);
560 VkFence nullFence = VK_NULL_HANDLE;
561 VkPipelineStageFlags pipe_stage_flags =
562 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
563 VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
565 .waitSemaphoreCount = 1,
566 .pWaitSemaphores = &presentCompleteSemaphore,
567 .pWaitDstStageMask = &pipe_stage_flags,
568 .commandBufferCount = 1,
569 .pCommandBuffers = &demo->draw_cmd,
570 .signalSemaphoreCount = 0,
571 .pSignalSemaphores = NULL};
573 err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence);
576 VkPresentInfoKHR present = {
577 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
580 .pSwapchains = &demo->swapchain,
581 .pImageIndices = &demo->current_buffer,
584 // TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER?
585 err = demo->fpQueuePresentKHR(demo->queue, &present);
586 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
587 // demo->swapchain is out of date (e.g. the window was resized) and
588 // must be recreated:
590 } else if (err == VK_SUBOPTIMAL_KHR) {
591 // demo->swapchain is not as optimal as it could be, but the platform's
592 // presentation engine will still present the image correctly.
597 err = vkQueueWaitIdle(demo->queue);
598 assert(err == VK_SUCCESS);
600 vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL);
603 static void demo_prepare_buffers(struct demo *demo) {
604 VkResult U_ASSERT_ONLY err;
605 VkSwapchainKHR oldSwapchain = demo->swapchain;
607 // Check the surface capabilities and formats
608 VkSurfaceCapabilitiesKHR surfCapabilities;
609 err = demo->fpGetPhysicalDeviceSurfaceCapabilitiesKHR(
610 demo->gpu, demo->surface, &surfCapabilities);
613 uint32_t presentModeCount;
614 err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(
615 demo->gpu, demo->surface, &presentModeCount, NULL);
617 VkPresentModeKHR *presentModes =
618 (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
619 assert(presentModes);
620 err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(
621 demo->gpu, demo->surface, &presentModeCount, presentModes);
624 VkExtent2D swapchainExtent;
625 // width and height are either both -1, or both not -1.
626 if (surfCapabilities.currentExtent.width == (uint32_t)-1) {
627 // If the surface size is undefined, the size is set to
628 // the size of the images requested.
629 swapchainExtent.width = demo->width;
630 swapchainExtent.height = demo->height;
632 // If the surface size is defined, the swap chain size must match
633 swapchainExtent = surfCapabilities.currentExtent;
634 demo->width = surfCapabilities.currentExtent.width;
635 demo->height = surfCapabilities.currentExtent.height;
638 VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
640 // Determine the number of VkImage's to use in the swap chain (we desire to
641 // own only 1 image at a time, besides the images being displayed and
642 // queued for display):
643 uint32_t desiredNumberOfSwapchainImages =
644 surfCapabilities.minImageCount + 1;
645 if ((surfCapabilities.maxImageCount > 0) &&
646 (desiredNumberOfSwapchainImages > surfCapabilities.maxImageCount)) {
647 // Application must settle for fewer images than desired:
648 desiredNumberOfSwapchainImages = surfCapabilities.maxImageCount;
651 VkSurfaceTransformFlagsKHR preTransform;
652 if (surfCapabilities.supportedTransforms &
653 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
654 preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
656 preTransform = surfCapabilities.currentTransform;
659 const VkSwapchainCreateInfoKHR swapchain = {
660 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
662 .surface = demo->surface,
663 .minImageCount = desiredNumberOfSwapchainImages,
664 .imageFormat = demo->format,
665 .imageColorSpace = demo->color_space,
668 .width = swapchainExtent.width, .height = swapchainExtent.height,
670 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
671 .preTransform = preTransform,
672 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
673 .imageArrayLayers = 1,
674 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
675 .queueFamilyIndexCount = 0,
676 .pQueueFamilyIndices = NULL,
677 .presentMode = swapchainPresentMode,
678 .oldSwapchain = oldSwapchain,
683 err = demo->fpCreateSwapchainKHR(demo->device, &swapchain, NULL,
687 // If we just re-created an existing swapchain, we should destroy the old
688 // swapchain at this point.
689 // Note: destroying the swapchain also cleans up all its associated
690 // presentable images once the platform is done with them.
691 if (oldSwapchain != VK_NULL_HANDLE) {
692 demo->fpDestroySwapchainKHR(demo->device, oldSwapchain, NULL);
695 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
696 &demo->swapchainImageCount, NULL);
699 VkImage *swapchainImages =
700 (VkImage *)malloc(demo->swapchainImageCount * sizeof(VkImage));
701 assert(swapchainImages);
702 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
703 &demo->swapchainImageCount,
707 demo->buffers = (SwapchainBuffers *)malloc(sizeof(SwapchainBuffers) *
708 demo->swapchainImageCount);
709 assert(demo->buffers);
711 for (i = 0; i < demo->swapchainImageCount; i++) {
712 VkImageViewCreateInfo color_attachment_view = {
713 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
715 .format = demo->format,
718 .r = VK_COMPONENT_SWIZZLE_R,
719 .g = VK_COMPONENT_SWIZZLE_G,
720 .b = VK_COMPONENT_SWIZZLE_B,
721 .a = VK_COMPONENT_SWIZZLE_A,
723 .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
728 .viewType = VK_IMAGE_VIEW_TYPE_2D,
732 demo->buffers[i].image = swapchainImages[i];
734 // Render loop will expect image to have been used before and in
735 // VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
736 // layout and will change to COLOR_ATTACHMENT_OPTIMAL, so init the image
738 demo_set_image_layout(
739 demo, demo->buffers[i].image, VK_IMAGE_ASPECT_COLOR_BIT,
740 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
743 color_attachment_view.image = demo->buffers[i].image;
745 err = vkCreateImageView(demo->device, &color_attachment_view, NULL,
746 &demo->buffers[i].view);
750 demo->current_buffer = 0;
752 if (NULL != presentModes) {
757 static void demo_prepare_depth(struct demo *demo) {
758 const VkFormat depth_format = VK_FORMAT_D16_UNORM;
759 const VkImageCreateInfo image = {
760 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
762 .imageType = VK_IMAGE_TYPE_2D,
763 .format = depth_format,
764 .extent = {demo->width, demo->height, 1},
767 .samples = VK_SAMPLE_COUNT_1_BIT,
768 .tiling = VK_IMAGE_TILING_OPTIMAL,
769 .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
772 VkMemoryAllocateInfo mem_alloc = {
773 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
776 .memoryTypeIndex = 0,
778 VkImageViewCreateInfo view = {
779 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
781 .image = VK_NULL_HANDLE,
782 .format = depth_format,
783 .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
789 .viewType = VK_IMAGE_VIEW_TYPE_2D,
792 VkMemoryRequirements mem_reqs;
793 VkResult U_ASSERT_ONLY err;
794 bool U_ASSERT_ONLY pass;
796 demo->depth.format = depth_format;
799 err = vkCreateImage(demo->device, &image, NULL, &demo->depth.image);
802 /* get memory requirements for this object */
803 vkGetImageMemoryRequirements(demo->device, demo->depth.image, &mem_reqs);
805 /* select memory size and type */
806 mem_alloc.allocationSize = mem_reqs.size;
807 pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
808 0, /* No requirements */
809 &mem_alloc.memoryTypeIndex);
812 /* allocate memory */
813 err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &demo->depth.mem);
818 vkBindImageMemory(demo->device, demo->depth.image, demo->depth.mem, 0);
821 demo_set_image_layout(demo, demo->depth.image, VK_IMAGE_ASPECT_DEPTH_BIT,
822 VK_IMAGE_LAYOUT_UNDEFINED,
823 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
826 /* create image view */
827 view.image = demo->depth.image;
828 err = vkCreateImageView(demo->device, &view, NULL, &demo->depth.view);
833 demo_prepare_texture_image(struct demo *demo, const uint32_t *tex_colors,
834 struct texture_object *tex_obj, VkImageTiling tiling,
835 VkImageUsageFlags usage, VkFlags required_props) {
836 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
837 const int32_t tex_width = 2;
838 const int32_t tex_height = 2;
839 VkResult U_ASSERT_ONLY err;
840 bool U_ASSERT_ONLY pass;
842 tex_obj->tex_width = tex_width;
843 tex_obj->tex_height = tex_height;
845 const VkImageCreateInfo image_create_info = {
846 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
848 .imageType = VK_IMAGE_TYPE_2D,
849 .format = tex_format,
850 .extent = {tex_width, tex_height, 1},
853 .samples = VK_SAMPLE_COUNT_1_BIT,
857 .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED
859 VkMemoryAllocateInfo mem_alloc = {
860 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
863 .memoryTypeIndex = 0,
866 VkMemoryRequirements mem_reqs;
869 vkCreateImage(demo->device, &image_create_info, NULL, &tex_obj->image);
872 vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs);
874 mem_alloc.allocationSize = mem_reqs.size;
876 memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
877 required_props, &mem_alloc.memoryTypeIndex);
880 /* allocate memory */
881 err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &tex_obj->mem);
885 err = vkBindImageMemory(demo->device, tex_obj->image, tex_obj->mem, 0);
888 if (required_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
889 const VkImageSubresource subres = {
890 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
894 VkSubresourceLayout layout;
898 vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres,
901 err = vkMapMemory(demo->device, tex_obj->mem, 0,
902 mem_alloc.allocationSize, 0, &data);
905 for (y = 0; y < tex_height; y++) {
906 uint32_t *row = (uint32_t *)((char *)data + layout.rowPitch * y);
907 for (x = 0; x < tex_width; x++)
908 row[x] = tex_colors[(x & 1) ^ (y & 1)];
911 vkUnmapMemory(demo->device, tex_obj->mem);
914 tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
915 demo_set_image_layout(demo, tex_obj->image, VK_IMAGE_ASPECT_COLOR_BIT,
916 VK_IMAGE_LAYOUT_PREINITIALIZED, tex_obj->imageLayout,
917 VK_ACCESS_HOST_WRITE_BIT);
918 /* setting the image layout does not reference the actual memory so no need
919 * to add a mem ref */
922 static void demo_destroy_texture_image(struct demo *demo,
923 struct texture_object *tex_obj) {
924 /* clean up staging resources */
925 vkDestroyImage(demo->device, tex_obj->image, NULL);
926 vkFreeMemory(demo->device, tex_obj->mem, NULL);
929 static void demo_prepare_textures(struct demo *demo) {
930 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
931 VkFormatProperties props;
932 const uint32_t tex_colors[DEMO_TEXTURE_COUNT][2] = {
933 {0xffff0000, 0xff00ff00},
936 VkResult U_ASSERT_ONLY err;
938 vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props);
940 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
941 if ((props.linearTilingFeatures &
942 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
943 !demo->use_staging_buffer) {
944 /* Device can texture using linear textures */
945 demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i],
946 VK_IMAGE_TILING_LINEAR,
947 VK_IMAGE_USAGE_SAMPLED_BIT,
948 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
949 } else if (props.optimalTilingFeatures &
950 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
951 /* Must use staging buffer to copy linear texture to optimized */
952 struct texture_object staging_texture;
954 memset(&staging_texture, 0, sizeof(staging_texture));
955 demo_prepare_texture_image(demo, tex_colors[i], &staging_texture,
956 VK_IMAGE_TILING_LINEAR,
957 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
958 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
960 demo_prepare_texture_image(
961 demo, tex_colors[i], &demo->textures[i],
962 VK_IMAGE_TILING_OPTIMAL,
963 (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT),
964 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
966 demo_set_image_layout(demo, staging_texture.image,
967 VK_IMAGE_ASPECT_COLOR_BIT,
968 staging_texture.imageLayout,
969 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
972 demo_set_image_layout(demo, demo->textures[i].image,
973 VK_IMAGE_ASPECT_COLOR_BIT,
974 demo->textures[i].imageLayout,
975 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
978 VkImageCopy copy_region = {
979 .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
980 .srcOffset = {0, 0, 0},
981 .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
982 .dstOffset = {0, 0, 0},
983 .extent = {staging_texture.tex_width,
984 staging_texture.tex_height, 1},
987 demo->setup_cmd, staging_texture.image,
988 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, demo->textures[i].image,
989 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
991 demo_set_image_layout(demo, demo->textures[i].image,
992 VK_IMAGE_ASPECT_COLOR_BIT,
993 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
994 demo->textures[i].imageLayout,
997 demo_flush_init_cmd(demo);
999 demo_destroy_texture_image(demo, &staging_texture);
1001 /* Can't support VK_FORMAT_B8G8R8A8_UNORM !? */
1002 assert(!"No support for B8G8R8A8_UNORM as texture image format");
1005 const VkSamplerCreateInfo sampler = {
1006 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
1008 .magFilter = VK_FILTER_NEAREST,
1009 .minFilter = VK_FILTER_NEAREST,
1010 .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
1011 .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
1012 .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
1013 .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
1015 .anisotropyEnable = VK_FALSE,
1017 .compareOp = VK_COMPARE_OP_NEVER,
1020 .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
1021 .unnormalizedCoordinates = VK_FALSE,
1023 VkImageViewCreateInfo view = {
1024 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1026 .image = VK_NULL_HANDLE,
1027 .viewType = VK_IMAGE_VIEW_TYPE_2D,
1028 .format = tex_format,
1031 VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
1032 VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A,
1034 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
1038 /* create sampler */
1039 err = vkCreateSampler(demo->device, &sampler, NULL,
1040 &demo->textures[i].sampler);
1043 /* create image view */
1044 view.image = demo->textures[i].image;
1045 err = vkCreateImageView(demo->device, &view, NULL,
1046 &demo->textures[i].view);
1051 static void demo_prepare_vertices(struct demo *demo) {
1053 const float vb[3][5] = {
1054 /* position texcoord */
1055 { -1.0f, -1.0f, 0.25f, 0.0f, 0.0f },
1056 { 1.0f, -1.0f, 0.25f, 1.0f, 0.0f },
1057 { 0.0f, 1.0f, 1.0f, 0.5f, 1.0f },
1060 const VkBufferCreateInfo buf_info = {
1061 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1064 .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
1067 VkMemoryAllocateInfo mem_alloc = {
1068 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1070 .allocationSize = 0,
1071 .memoryTypeIndex = 0,
1073 VkMemoryRequirements mem_reqs;
1074 VkResult U_ASSERT_ONLY err;
1075 bool U_ASSERT_ONLY pass;
1078 memset(&demo->vertices, 0, sizeof(demo->vertices));
1080 err = vkCreateBuffer(demo->device, &buf_info, NULL, &demo->vertices.buf);
1083 vkGetBufferMemoryRequirements(demo->device, demo->vertices.buf, &mem_reqs);
1086 mem_alloc.allocationSize = mem_reqs.size;
1087 pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
1088 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
1089 &mem_alloc.memoryTypeIndex);
1092 err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &demo->vertices.mem);
1095 err = vkMapMemory(demo->device, demo->vertices.mem, 0,
1096 mem_alloc.allocationSize, 0, &data);
1099 memcpy(data, vb, sizeof(vb));
1101 vkUnmapMemory(demo->device, demo->vertices.mem);
1103 err = vkBindBufferMemory(demo->device, demo->vertices.buf,
1104 demo->vertices.mem, 0);
1107 demo->vertices.vi.sType =
1108 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
1109 demo->vertices.vi.pNext = NULL;
1110 demo->vertices.vi.vertexBindingDescriptionCount = 1;
1111 demo->vertices.vi.pVertexBindingDescriptions = demo->vertices.vi_bindings;
1112 demo->vertices.vi.vertexAttributeDescriptionCount = 2;
1113 demo->vertices.vi.pVertexAttributeDescriptions = demo->vertices.vi_attrs;
1115 demo->vertices.vi_bindings[0].binding = VERTEX_BUFFER_BIND_ID;
1116 demo->vertices.vi_bindings[0].stride = sizeof(vb[0]);
1117 demo->vertices.vi_bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1119 demo->vertices.vi_attrs[0].binding = VERTEX_BUFFER_BIND_ID;
1120 demo->vertices.vi_attrs[0].location = 0;
1121 demo->vertices.vi_attrs[0].format = VK_FORMAT_R32G32B32_SFLOAT;
1122 demo->vertices.vi_attrs[0].offset = 0;
1124 demo->vertices.vi_attrs[1].binding = VERTEX_BUFFER_BIND_ID;
1125 demo->vertices.vi_attrs[1].location = 1;
1126 demo->vertices.vi_attrs[1].format = VK_FORMAT_R32G32_SFLOAT;
1127 demo->vertices.vi_attrs[1].offset = sizeof(float) * 3;
1130 static void demo_prepare_descriptor_layout(struct demo *demo) {
1131 const VkDescriptorSetLayoutBinding layout_binding = {
1133 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1134 .descriptorCount = DEMO_TEXTURE_COUNT,
1135 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
1136 .pImmutableSamplers = NULL,
1138 const VkDescriptorSetLayoutCreateInfo descriptor_layout = {
1139 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
1142 .pBindings = &layout_binding,
1144 VkResult U_ASSERT_ONLY err;
1146 err = vkCreateDescriptorSetLayout(demo->device, &descriptor_layout, NULL,
1147 &demo->desc_layout);
1150 const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {
1151 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1153 .setLayoutCount = 1,
1154 .pSetLayouts = &demo->desc_layout,
1157 err = vkCreatePipelineLayout(demo->device, &pPipelineLayoutCreateInfo, NULL,
1158 &demo->pipeline_layout);
1162 static void demo_prepare_render_pass(struct demo *demo) {
1163 const VkAttachmentDescription attachments[2] = {
1166 .format = demo->format,
1167 .samples = VK_SAMPLE_COUNT_1_BIT,
1168 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1169 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
1170 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1171 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1172 .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1173 .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1177 .format = demo->depth.format,
1178 .samples = VK_SAMPLE_COUNT_1_BIT,
1179 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1180 .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1181 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1182 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1184 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1186 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1189 const VkAttachmentReference color_reference = {
1190 .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1192 const VkAttachmentReference depth_reference = {
1194 .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1196 const VkSubpassDescription subpass = {
1197 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
1199 .inputAttachmentCount = 0,
1200 .pInputAttachments = NULL,
1201 .colorAttachmentCount = 1,
1202 .pColorAttachments = &color_reference,
1203 .pResolveAttachments = NULL,
1204 .pDepthStencilAttachment = &depth_reference,
1205 .preserveAttachmentCount = 0,
1206 .pPreserveAttachments = NULL,
1208 const VkRenderPassCreateInfo rp_info = {
1209 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
1211 .attachmentCount = 2,
1212 .pAttachments = attachments,
1214 .pSubpasses = &subpass,
1215 .dependencyCount = 0,
1216 .pDependencies = NULL,
1218 VkResult U_ASSERT_ONLY err;
1220 err = vkCreateRenderPass(demo->device, &rp_info, NULL, &demo->render_pass);
1224 static VkShaderModule
1225 demo_prepare_shader_module(struct demo *demo, const void *code, size_t size) {
1226 VkShaderModuleCreateInfo moduleCreateInfo;
1227 VkShaderModule module;
1228 VkResult U_ASSERT_ONLY err;
1230 moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1231 moduleCreateInfo.pNext = NULL;
1233 moduleCreateInfo.codeSize = size;
1234 moduleCreateInfo.pCode = code;
1235 moduleCreateInfo.flags = 0;
1236 err = vkCreateShaderModule(demo->device, &moduleCreateInfo, NULL, &module);
1242 char *demo_read_spv(const char *filename, size_t *psize) {
1247 FILE *fp = fopen(filename, "rb");
1251 fseek(fp, 0L, SEEK_END);
1254 fseek(fp, 0L, SEEK_SET);
1256 shader_code = malloc(size);
1257 retVal = fread(shader_code, size, 1, fp);
1267 static unsigned char vert_spirv_bin[] = {
1268 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00,
1269 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
1270 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,
1271 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1272 0x0F, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
1273 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1274 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
1275 0x04, 0x00, 0x09, 0x00, 0x47, 0x4C, 0x5F, 0x41, 0x52, 0x42, 0x5F, 0x73, 0x65, 0x70, 0x61, 0x72,
1276 0x61, 0x74, 0x65, 0x5F, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5F, 0x6F, 0x62, 0x6A, 0x65, 0x63,
1277 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4C, 0x5F, 0x41, 0x52, 0x42, 0x5F, 0x73,
1278 0x68, 0x61, 0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, 0x5F,
1279 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6B, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
1280 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00,
1281 0x74, 0x65, 0x78, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
1282 0x0B, 0x00, 0x00, 0x00, 0x61, 0x74, 0x74, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00,
1283 0x0E, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
1284 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1285 0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x05, 0x00, 0x03, 0x00,
1286 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00,
1287 0x70, 0x6F, 0x73, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
1288 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
1289 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1290 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00,
1291 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
1292 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
1293 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00,
1294 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
1295 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1296 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
1297 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1298 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
1299 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
1300 0x04, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
1301 0x20, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
1302 0x3B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1303 0x15, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1304 0x2B, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1305 0x20, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
1306 0x3B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1307 0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
1308 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1309 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
1310 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
1311 0x09, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00,
1312 0x15, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x16, 0x00, 0x00, 0x00,
1313 0x17, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
1314 0x17, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
1317 static VkShaderModule demo_prepare_vs(struct demo *demo) {
1318 void *vertShaderCode;
1321 /* insert shader binary for test convenience */
1322 /* vertShaderCode = demo_read_spv("tri-vert.spv", &size);*/
1323 vertShaderCode = vert_spirv_bin;
1324 size = sizeof(vert_spirv_bin)/sizeof(unsigned char);
1326 demo->vert_shader_module =
1327 demo_prepare_shader_module(demo, vertShaderCode, size);
1329 /*free(vertShaderCode);*/
1331 return demo->vert_shader_module;
1334 static unsigned char frag_spirv_bin[] = {
1335 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00,
1336 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
1337 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,
1338 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1339 0x0F, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
1340 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
1341 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
1342 0x90, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4C, 0x5F, 0x41, 0x52, 0x42, 0x5F, 0x73,
1343 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5F, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5F, 0x6F,
1344 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4C, 0x5F, 0x41,
1345 0x52, 0x42, 0x5F, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6C, 0x61, 0x6E, 0x67, 0x75,
1346 0x61, 0x67, 0x65, 0x5F, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6B, 0x00, 0x05, 0x00, 0x04, 0x00,
1347 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
1348 0x09, 0x00, 0x00, 0x00, 0x75, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00,
1349 0x05, 0x00, 0x03, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x00, 0x05, 0x00, 0x05, 0x00,
1350 0x11, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00,
1351 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1352 0x47, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1353 0x47, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1354 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1355 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
1356 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
1357 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1358 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
1359 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1360 0x19, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1362 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
1363 0x20, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
1364 0x3B, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1365 0x17, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1366 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
1367 0x3B, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1368 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1369 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
1370 0x0B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
1371 0x0F, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00,
1372 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
1373 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00,
1374 0x38, 0x00, 0x01, 0x00,
1377 static VkShaderModule demo_prepare_fs(struct demo *demo) {
1378 void *fragShaderCode;
1381 /* insert shader binary for test convenience */
1382 /*fragShaderCode = demo_read_spv("tri-frag.spv", &size);*/
1383 fragShaderCode = frag_spirv_bin;
1384 size = sizeof(frag_spirv_bin)/sizeof(unsigned char);
1386 demo->frag_shader_module =
1387 demo_prepare_shader_module(demo, fragShaderCode, size);
1389 /*free(fragShaderCode);*/
1391 return demo->frag_shader_module;
1394 static void demo_prepare_pipeline(struct demo *demo) {
1395 VkGraphicsPipelineCreateInfo pipeline;
1396 VkPipelineCacheCreateInfo pipelineCache;
1398 VkPipelineVertexInputStateCreateInfo vi;
1399 VkPipelineInputAssemblyStateCreateInfo ia;
1400 VkPipelineRasterizationStateCreateInfo rs;
1401 VkPipelineColorBlendStateCreateInfo cb;
1402 VkPipelineDepthStencilStateCreateInfo ds;
1403 VkPipelineViewportStateCreateInfo vp;
1404 VkPipelineMultisampleStateCreateInfo ms;
1405 VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE];
1406 VkPipelineDynamicStateCreateInfo dynamicState;
1408 VkResult U_ASSERT_ONLY err;
1410 memset(dynamicStateEnables, 0, sizeof dynamicStateEnables);
1411 memset(&dynamicState, 0, sizeof dynamicState);
1412 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
1413 dynamicState.pDynamicStates = dynamicStateEnables;
1415 memset(&pipeline, 0, sizeof(pipeline));
1416 pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
1417 pipeline.layout = demo->pipeline_layout;
1419 vi = demo->vertices.vi;
1421 memset(&ia, 0, sizeof(ia));
1422 ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
1423 ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1425 memset(&rs, 0, sizeof(rs));
1426 rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
1427 rs.polygonMode = VK_POLYGON_MODE_FILL;
1428 rs.cullMode = VK_CULL_MODE_BACK_BIT;
1429 rs.frontFace = VK_FRONT_FACE_CLOCKWISE;
1430 rs.depthClampEnable = VK_FALSE;
1431 rs.rasterizerDiscardEnable = VK_FALSE;
1432 rs.depthBiasEnable = VK_FALSE;
1434 memset(&cb, 0, sizeof(cb));
1435 cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
1436 VkPipelineColorBlendAttachmentState att_state[1];
1437 memset(att_state, 0, sizeof(att_state));
1438 att_state[0].colorWriteMask = 0xf;
1439 att_state[0].blendEnable = VK_FALSE;
1440 cb.attachmentCount = 1;
1441 cb.pAttachments = att_state;
1443 memset(&vp, 0, sizeof(vp));
1444 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
1445 vp.viewportCount = 1;
1446 dynamicStateEnables[dynamicState.dynamicStateCount++] =
1447 VK_DYNAMIC_STATE_VIEWPORT;
1448 vp.scissorCount = 1;
1449 dynamicStateEnables[dynamicState.dynamicStateCount++] =
1450 VK_DYNAMIC_STATE_SCISSOR;
1452 memset(&ds, 0, sizeof(ds));
1453 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
1454 ds.depthTestEnable = VK_TRUE;
1455 ds.depthWriteEnable = VK_TRUE;
1456 ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
1457 ds.depthBoundsTestEnable = VK_FALSE;
1458 ds.back.failOp = VK_STENCIL_OP_KEEP;
1459 ds.back.passOp = VK_STENCIL_OP_KEEP;
1460 ds.back.compareOp = VK_COMPARE_OP_ALWAYS;
1461 ds.stencilTestEnable = VK_FALSE;
1464 memset(&ms, 0, sizeof(ms));
1465 ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
1466 ms.pSampleMask = NULL;
1467 ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
1469 // Two stages: vs and fs
1470 pipeline.stageCount = 2;
1471 VkPipelineShaderStageCreateInfo shaderStages[2];
1472 memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo));
1474 shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1475 shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
1476 shaderStages[0].module = demo_prepare_vs(demo);
1477 shaderStages[0].pName = "main";
1479 shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1480 shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1481 shaderStages[1].module = demo_prepare_fs(demo);
1482 shaderStages[1].pName = "main";
1484 pipeline.pVertexInputState = &vi;
1485 pipeline.pInputAssemblyState = &ia;
1486 pipeline.pRasterizationState = &rs;
1487 pipeline.pColorBlendState = &cb;
1488 pipeline.pMultisampleState = &ms;
1489 pipeline.pViewportState = &vp;
1490 pipeline.pDepthStencilState = &ds;
1491 pipeline.pStages = shaderStages;
1492 pipeline.renderPass = demo->render_pass;
1493 pipeline.pDynamicState = &dynamicState;
1495 memset(&pipelineCache, 0, sizeof(pipelineCache));
1496 pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
1498 err = vkCreatePipelineCache(demo->device, &pipelineCache, NULL,
1499 &demo->pipelineCache);
1501 err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1,
1502 &pipeline, NULL, &demo->pipeline);
1505 vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL);
1507 vkDestroyShaderModule(demo->device, demo->frag_shader_module, NULL);
1508 vkDestroyShaderModule(demo->device, demo->vert_shader_module, NULL);
1511 static void demo_prepare_descriptor_pool(struct demo *demo) {
1512 const VkDescriptorPoolSize type_count = {
1513 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1514 .descriptorCount = DEMO_TEXTURE_COUNT,
1516 const VkDescriptorPoolCreateInfo descriptor_pool = {
1517 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1521 .pPoolSizes = &type_count,
1523 VkResult U_ASSERT_ONLY err;
1525 err = vkCreateDescriptorPool(demo->device, &descriptor_pool, NULL,
1530 static void demo_prepare_descriptor_set(struct demo *demo) {
1531 VkDescriptorImageInfo tex_descs[DEMO_TEXTURE_COUNT];
1532 VkWriteDescriptorSet write;
1533 VkResult U_ASSERT_ONLY err;
1536 VkDescriptorSetAllocateInfo alloc_info = {
1537 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1539 .descriptorPool = demo->desc_pool,
1540 .descriptorSetCount = 1,
1541 .pSetLayouts = &demo->desc_layout};
1542 err = vkAllocateDescriptorSets(demo->device, &alloc_info, &demo->desc_set);
1545 memset(&tex_descs, 0, sizeof(tex_descs));
1546 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1547 tex_descs[i].sampler = demo->textures[i].sampler;
1548 tex_descs[i].imageView = demo->textures[i].view;
1549 tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
1552 memset(&write, 0, sizeof(write));
1553 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1554 write.dstSet = demo->desc_set;
1555 write.descriptorCount = DEMO_TEXTURE_COUNT;
1556 write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1557 write.pImageInfo = tex_descs;
1559 vkUpdateDescriptorSets(demo->device, 1, &write, 0, NULL);
1562 static void demo_prepare_framebuffers(struct demo *demo) {
1563 VkImageView attachments[2];
1564 attachments[1] = demo->depth.view;
1566 const VkFramebufferCreateInfo fb_info = {
1567 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1569 .renderPass = demo->render_pass,
1570 .attachmentCount = 2,
1571 .pAttachments = attachments,
1572 .width = demo->width,
1573 .height = demo->height,
1576 VkResult U_ASSERT_ONLY err;
1579 demo->framebuffers = (VkFramebuffer *)malloc(demo->swapchainImageCount *
1580 sizeof(VkFramebuffer));
1581 assert(demo->framebuffers);
1583 for (i = 0; i < demo->swapchainImageCount; i++) {
1584 attachments[0] = demo->buffers[i].view;
1585 err = vkCreateFramebuffer(demo->device, &fb_info, NULL,
1586 &demo->framebuffers[i]);
1591 static void demo_prepare(struct demo *demo) {
1592 VkResult U_ASSERT_ONLY err;
1594 const VkCommandPoolCreateInfo cmd_pool_info = {
1595 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1597 .queueFamilyIndex = demo->graphics_queue_node_index,
1598 .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
1600 err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL,
1604 const VkCommandBufferAllocateInfo cmd = {
1605 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1607 .commandPool = demo->cmd_pool,
1608 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1609 .commandBufferCount = 1,
1611 err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->draw_cmd);
1614 demo_prepare_buffers(demo);
1615 demo_prepare_depth(demo);
1616 demo_prepare_textures(demo);
1617 demo_prepare_vertices(demo);
1618 demo_prepare_descriptor_layout(demo);
1619 demo_prepare_render_pass(demo);
1620 demo_prepare_pipeline(demo);
1622 demo_prepare_descriptor_pool(demo);
1623 demo_prepare_descriptor_set(demo);
1625 demo_prepare_framebuffers(demo);
1627 demo->prepared = true;
1631 static void demo_run(struct demo *demo) {
1632 if (!demo->prepared)
1636 if (demo->depthStencil > 0.99f)
1637 demo->depthIncrement = -0.001f;
1638 if (demo->depthStencil < 0.8f)
1639 demo->depthIncrement = 0.001f;
1641 demo->depthStencil += demo->depthIncrement;
1644 if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) {
1645 PostQuitMessage(validation_error);
1649 // On MS-Windows, make this a global, so it's available to WndProc()
1652 // MS-Windows event handling function:
1653 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
1654 char tmp_str[] = APP_LONG_NAME;
1660 PostQuitMessage(validation_error);
1663 if (demo.prepared) {
1668 // Resize the application to the new window size, except when
1669 // it was minimized. Vulkan doesn't support images or swapchains
1670 // with width=0 and height=0.
1671 if (wParam != SIZE_MINIMIZED) {
1672 demo.width = lParam & 0xffff;
1673 demo.height = lParam & 0xffff0000 >> 16;
1680 return (DefWindowProc(hWnd, uMsg, wParam, lParam));
1683 static void demo_create_window(struct demo *demo) {
1684 WNDCLASSEX win_class;
1686 // Initialize the window class structure:
1687 win_class.cbSize = sizeof(WNDCLASSEX);
1688 win_class.style = CS_HREDRAW | CS_VREDRAW;
1689 win_class.lpfnWndProc = WndProc;
1690 win_class.cbClsExtra = 0;
1691 win_class.cbWndExtra = 0;
1692 win_class.hInstance = demo->connection; // hInstance
1693 win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1694 win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
1695 win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
1696 win_class.lpszMenuName = NULL;
1697 win_class.lpszClassName = demo->name;
1698 win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
1699 // Register window class:
1700 if (!RegisterClassEx(&win_class)) {
1701 // It didn't work, so try to give a useful error:
1702 printf("Unexpected error trying to start the application!\n");
1706 // Create window with the registered class:
1707 RECT wr = {0, 0, demo->width, demo->height};
1708 AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
1709 demo->window = CreateWindowEx(0,
1710 demo->name, // class name
1711 demo->name, // app name
1712 WS_OVERLAPPEDWINDOW | // window style
1713 WS_VISIBLE | WS_SYSMENU,
1714 100, 100, // x/y coords
1715 wr.right - wr.left, // width
1716 wr.bottom - wr.top, // height
1717 NULL, // handle to parent
1718 NULL, // handle to menu
1719 demo->connection, // hInstance
1720 NULL); // no extra parameters
1721 if (!demo->window) {
1722 // It didn't work, so try to give a useful error:
1723 printf("Cannot create a window in which to draw!\n");
1730 static void demo_run(struct demo *demo) {
1732 while (!demo->quit) {
1735 if (demo->depthStencil > 0.99f)
1736 demo->depthIncrement = -0.001f;
1737 if (demo->depthStencil < 0.8f)
1738 demo->depthIncrement = 0.001f;
1740 demo->depthStencil += demo->depthIncrement;
1742 // Wait for work to finish before updating MVP.
1743 vkDeviceWaitIdle(demo->device);
1745 if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
1752 handle_ping(void *data, struct wl_shell_surface *shell_surface,
1754 printf("%s\n", __func__);
1755 wl_shell_surface_pong(shell_surface, serial);
1759 handle_configure(void *data, struct wl_shell_surface *shell_surface,
1760 uint32_t edges, int32_t width, int32_t height) {
1761 printf("%s, (%d, %d)\n", __func__, width, height);
1765 handle_popup_done(void *data, struct wl_shell_surface *shell_surface) {
1768 static const struct wl_shell_surface_listener shell_surface_listener = {
1774 static void demo_create_window(struct demo *demo) {
1775 demo->wl_surface = wl_compositor_create_surface(demo->compositor);
1777 demo->shell_surface = wl_shell_get_shell_surface(demo->shell, demo->wl_surface);
1779 if (demo->shell_surface) {
1780 wl_shell_surface_add_listener(demo->shell_surface,
1781 &shell_surface_listener, demo);
1782 wl_shell_surface_set_toplevel(demo->shell_surface);
1785 wl_surface_set_user_data(demo->wl_surface, demo);
1786 wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME);
1791 * Return 1 (true) if all layer names specified in check_names
1792 * can be found in given layer properties.
1794 static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
1795 uint32_t layer_count,
1796 VkLayerProperties *layers) {
1798 for (i = 0; i < check_count; i++) {
1800 for (j = 0; j < layer_count; j++) {
1801 if (!strcmp(check_names[i], layers[j].layerName)) {
1807 fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
1814 static void demo_init_vk(struct demo *demo) {
1816 uint32_t instance_extension_count = 0;
1817 uint32_t instance_layer_count = 0;
1818 uint32_t device_validation_layer_count = 0;
1819 char **instance_validation_layers = NULL;
1821 demo->enabled_extension_count = 0;
1822 demo->enabled_layer_count = 0;
1824 char *instance_validation_layers_alt1[] = {
1825 "VK_LAYER_LUNARG_standard_validation"
1828 char *instance_validation_layers_alt2[] = {
1829 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation",
1830 "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker",
1831 "VK_LAYER_LUNARG_image", "VK_LAYER_LUNARG_core_validation",
1832 "VK_LAYER_LUNARG_swapchain", "VK_LAYER_GOOGLE_unique_objects"
1835 /* Look for validation layers */
1836 VkBool32 validation_found = 0;
1837 if (demo->validate) {
1839 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
1842 instance_validation_layers = instance_validation_layers_alt1;
1843 if (instance_layer_count > 0) {
1844 VkLayerProperties *instance_layers =
1845 malloc(sizeof (VkLayerProperties) * instance_layer_count);
1846 err = vkEnumerateInstanceLayerProperties(&instance_layer_count,
1851 validation_found = demo_check_layers(
1852 ARRAY_SIZE(instance_validation_layers_alt1),
1853 instance_validation_layers, instance_layer_count,
1855 if (validation_found) {
1856 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
1857 demo->device_validation_layers[0] = "VK_LAYER_LUNARG_standard_validation";
1858 device_validation_layer_count = 1;
1860 // use alternative set of validation layers
1861 instance_validation_layers = instance_validation_layers_alt2;
1862 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
1863 validation_found = demo_check_layers(
1864 ARRAY_SIZE(instance_validation_layers_alt2),
1865 instance_validation_layers, instance_layer_count,
1867 device_validation_layer_count =
1868 ARRAY_SIZE(instance_validation_layers_alt2);
1869 for (i = 0; i < device_validation_layer_count; i++) {
1870 demo->device_validation_layers[i] =
1871 instance_validation_layers[i];
1874 free(instance_layers);
1877 if (!validation_found) {
1878 ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find"
1879 "required validation layer.\n\n"
1880 "Please look at the Getting Started guide for additional "
1882 "vkCreateInstance Failure");
1886 /* Look for instance extensions */
1887 VkBool32 surfaceExtFound = 0;
1888 VkBool32 platformSurfaceExtFound = 0;
1889 memset(demo->extension_names, 0, sizeof(demo->extension_names));
1891 err = vkEnumerateInstanceExtensionProperties(
1892 NULL, &instance_extension_count, NULL);
1895 if (instance_extension_count > 0) {
1897 VkExtensionProperties *instance_extensions =
1898 malloc(sizeof(VkExtensionProperties) * instance_extension_count);
1899 err = vkEnumerateInstanceExtensionProperties(
1900 NULL, &instance_extension_count, instance_extensions);
1902 for (i = 0; i < instance_extension_count; i++) {
1903 if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME,
1904 instance_extensions[i].extensionName)) {
1905 surfaceExtFound = 1;
1906 demo->extension_names[demo->enabled_extension_count++] =
1907 VK_KHR_SURFACE_EXTENSION_NAME;
1910 if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
1911 instance_extensions[i].extensionName)) {
1912 platformSurfaceExtFound = 1;
1913 demo->extension_names[demo->enabled_extension_count++] =
1914 VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
1917 if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
1918 instance_extensions[i].extensionName)) {
1919 platformSurfaceExtFound = 1;
1920 demo->extension_names[demo->enabled_extension_count++] =
1921 VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
1924 if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
1925 instance_extensions[i].extensionName)) {
1926 if (demo->validate) {
1927 demo->extension_names[demo->enabled_extension_count++] =
1928 VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
1931 assert(demo->enabled_extension_count < 64);
1934 free(instance_extensions);
1937 if (!surfaceExtFound) {
1938 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1939 "the " VK_KHR_SURFACE_EXTENSION_NAME
1940 " extension.\n\nDo you have a compatible "
1941 "Vulkan installable client driver (ICD) installed?\nPlease "
1942 "look at the Getting Started guide for additional "
1944 "vkCreateInstance Failure");
1946 if (!platformSurfaceExtFound) {
1948 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1949 "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME
1950 " extension.\n\nDo you have a compatible "
1951 "Vulkan installable client driver (ICD) installed?\nPlease "
1952 "look at the Getting Started guide for additional "
1954 "vkCreateInstance Failure");
1956 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1957 "the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
1958 " extension.\n\nDo you have a compatible "
1959 "Vulkan installable client driver (ICD) installed?\nPlease "
1960 "look at the Getting Started guide for additional "
1962 "vkCreateInstance Failure");
1965 const VkApplicationInfo app = {
1966 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
1968 .pApplicationName = APP_SHORT_NAME,
1969 .applicationVersion = 0,
1970 .pEngineName = APP_SHORT_NAME,
1972 .apiVersion = VK_API_VERSION_1_0,
1974 VkInstanceCreateInfo inst_info = {
1975 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
1977 .pApplicationInfo = &app,
1978 .enabledLayerCount = demo->enabled_layer_count,
1979 .ppEnabledLayerNames = (const char *const *)instance_validation_layers,
1980 .enabledExtensionCount = demo->enabled_extension_count,
1981 .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
1986 err = vkCreateInstance(&inst_info, NULL, &demo->inst);
1987 if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
1988 ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
1989 "(ICD).\n\nPlease look at the Getting Started guide for "
1990 "additional information.\n",
1991 "vkCreateInstance Failure");
1992 } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
1993 ERR_EXIT("Cannot find a specified extension library"
1994 ".\nMake sure your layers path is set appropriately\n",
1995 "vkCreateInstance Failure");
1997 ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
1998 "installable client driver (ICD) installed?\nPlease look at "
1999 "the Getting Started guide for additional information.\n",
2000 "vkCreateInstance Failure");
2003 /* Make initial call to query gpu_count, then second call for gpu info*/
2004 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
2005 assert(!err && gpu_count > 0);
2007 if (gpu_count > 0) {
2008 VkPhysicalDevice *physical_devices =
2009 malloc(sizeof(VkPhysicalDevice) * gpu_count);
2010 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count,
2013 /* For tri demo we just grab the first physical device */
2014 demo->gpu = physical_devices[0];
2015 free(physical_devices);
2017 ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible devices."
2018 "\n\nDo you have a compatible Vulkan installable client"
2019 " driver (ICD) installed?\nPlease look at the Getting Started"
2020 " guide for additional information.\n",
2021 "vkEnumeratePhysicalDevices Failure");
2024 /* Look for validation layers */
2025 if (demo->validate) {
2026 validation_found = 0;
2027 demo->enabled_layer_count = 0;
2028 uint32_t device_layer_count = 0;
2030 vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, NULL);
2033 if (device_layer_count > 0) {
2034 VkLayerProperties *device_layers =
2035 malloc(sizeof (VkLayerProperties) * device_layer_count);
2036 err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count,
2041 validation_found = demo_check_layers(device_validation_layer_count,
2042 demo->device_validation_layers,
2045 demo->enabled_layer_count = device_validation_layer_count;
2047 free(device_layers);
2050 if (!validation_found) {
2051 ERR_EXIT("vkEnumerateDeviceLayerProperties failed to find "
2052 "a required validation layer.\n\n"
2053 "Please look at the Getting Started guide for additional "
2055 "vkCreateDevice Failure");
2059 /* Look for device extensions */
2060 uint32_t device_extension_count = 0;
2061 VkBool32 swapchainExtFound = 0;
2062 demo->enabled_extension_count = 0;
2063 memset(demo->extension_names, 0, sizeof(demo->extension_names));
2065 err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL,
2066 &device_extension_count, NULL);
2069 if (device_extension_count > 0) {
2071 VkExtensionProperties *device_extensions =
2072 malloc(sizeof(VkExtensionProperties) * device_extension_count);
2073 err = vkEnumerateDeviceExtensionProperties(
2074 demo->gpu, NULL, &device_extension_count, device_extensions);
2077 for (i = 0; i < device_extension_count; i++) {
2078 if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,
2079 device_extensions[i].extensionName)) {
2080 swapchainExtFound = 1;
2081 demo->extension_names[demo->enabled_extension_count++] =
2082 VK_KHR_SWAPCHAIN_EXTENSION_NAME;
2084 assert(demo->enabled_extension_count < 64);
2087 free(device_extensions);
2090 if (!swapchainExtFound) {
2091 ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find "
2092 "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME
2093 " extension.\n\nDo you have a compatible "
2094 "Vulkan installable client driver (ICD) installed?\nPlease "
2095 "look at the Getting Started guide for additional "
2097 "vkCreateInstance Failure");
2100 if (demo->validate) {
2101 demo->CreateDebugReportCallback =
2102 (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(
2103 demo->inst, "vkCreateDebugReportCallbackEXT");
2104 demo->DestroyDebugReportCallback =
2105 (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(
2106 demo->inst, "vkDestroyDebugReportCallbackEXT");
2107 if (!demo->CreateDebugReportCallback) {
2109 "GetProcAddr: Unable to find vkCreateDebugReportCallbackEXT\n",
2110 "vkGetProcAddr Failure");
2112 if (!demo->DestroyDebugReportCallback) {
2114 "GetProcAddr: Unable to find vkDestroyDebugReportCallbackEXT\n",
2115 "vkGetProcAddr Failure");
2117 demo->DebugReportMessage =
2118 (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(
2119 demo->inst, "vkDebugReportMessageEXT");
2120 if (!demo->DebugReportMessage) {
2121 ERR_EXIT("GetProcAddr: Unable to find vkDebugReportMessageEXT\n",
2122 "vkGetProcAddr Failure");
2125 VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
2126 dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
2127 dbgCreateInfo.flags =
2128 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
2129 dbgCreateInfo.pfnCallback = demo->use_break ? BreakCallback : dbgFunc;
2130 dbgCreateInfo.pUserData = NULL;
2131 dbgCreateInfo.pNext = NULL;
2132 err = demo->CreateDebugReportCallback(demo->inst, &dbgCreateInfo, NULL,
2133 &demo->msg_callback);
2137 case VK_ERROR_OUT_OF_HOST_MEMORY:
2138 ERR_EXIT("CreateDebugReportCallback: out of host memory\n",
2139 "CreateDebugReportCallback Failure");
2142 ERR_EXIT("CreateDebugReportCallback: unknown failure\n",
2143 "CreateDebugReportCallback Failure");
2148 // Having these GIPA queries of device extension entry points both
2149 // BEFORE and AFTER vkCreateDevice is a good test for the loader
2150 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceCapabilitiesKHR);
2151 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR);
2152 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR);
2153 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR);
2154 GET_INSTANCE_PROC_ADDR(demo->inst, CreateSwapchainKHR);
2155 GET_INSTANCE_PROC_ADDR(demo->inst, DestroySwapchainKHR);
2156 GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR);
2157 GET_INSTANCE_PROC_ADDR(demo->inst, AcquireNextImageKHR);
2158 GET_INSTANCE_PROC_ADDR(demo->inst, QueuePresentKHR);
2160 vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
2162 // Query with NULL data to get count
2163 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
2166 demo->queue_props = (VkQueueFamilyProperties *)malloc(
2167 demo->queue_count * sizeof(VkQueueFamilyProperties));
2168 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
2170 assert(demo->queue_count >= 1);
2172 VkPhysicalDeviceFeatures features;
2173 vkGetPhysicalDeviceFeatures(demo->gpu, &features);
2175 if (!features.shaderClipDistance) {
2176 ERR_EXIT("Required device feature `shaderClipDistance` not supported\n",
2177 "GetPhysicalDeviceFeatures failure");
2180 // Graphics queue and MemMgr queue can be separate.
2181 // TODO: Add support for separate queues, including synchronization,
2182 // and appropriate tracking for QueueSubmit
2185 static void demo_init_device(struct demo *demo) {
2186 VkResult U_ASSERT_ONLY err;
2188 float queue_priorities[1] = {0.0};
2189 const VkDeviceQueueCreateInfo queue = {
2190 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
2192 .queueFamilyIndex = demo->graphics_queue_node_index,
2194 .pQueuePriorities = queue_priorities};
2196 VkPhysicalDeviceFeatures features = {
2197 .shaderClipDistance = VK_TRUE,
2200 VkDeviceCreateInfo device = {
2201 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
2203 .queueCreateInfoCount = 1,
2204 .pQueueCreateInfos = &queue,
2205 .enabledLayerCount = demo->enabled_layer_count,
2206 .ppEnabledLayerNames =
2207 (const char *const *)((demo->validate)
2208 ? demo->device_validation_layers
2210 .enabledExtensionCount = demo->enabled_extension_count,
2211 .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
2212 .pEnabledFeatures = &features,
2215 err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
2219 static void demo_init_vk_swapchain(struct demo *demo) {
2220 VkResult U_ASSERT_ONLY err;
2223 // Create a WSI surface for the window:
2225 VkWin32SurfaceCreateInfoKHR createInfo;
2226 createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
2227 createInfo.pNext = NULL;
2228 createInfo.flags = 0;
2229 createInfo.hinstance = demo->connection;
2230 createInfo.hwnd = demo->window;
2233 vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
2236 VkWaylandSurfaceCreateInfoKHR createInfo;
2237 createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
2238 createInfo.pNext = NULL;
2239 createInfo.flags = 0;
2240 createInfo.display = demo->display;
2241 createInfo.surface = demo->wl_surface;
2243 err = vkCreateWaylandSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
2246 // Iterate over each queue to learn whether it supports presenting:
2247 VkBool32 *supportsPresent =
2248 (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32));
2249 for (i = 0; i < demo->queue_count; i++) {
2250 demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface,
2251 &supportsPresent[i]);
2254 // Search for a graphics and a present queue in the array of queue
2255 // families, try to find one that supports both
2256 uint32_t graphicsQueueNodeIndex = UINT32_MAX;
2257 uint32_t presentQueueNodeIndex = UINT32_MAX;
2258 for (i = 0; i < demo->queue_count; i++) {
2259 if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
2260 if (graphicsQueueNodeIndex == UINT32_MAX) {
2261 graphicsQueueNodeIndex = i;
2264 if (supportsPresent[i] == VK_TRUE) {
2265 graphicsQueueNodeIndex = i;
2266 presentQueueNodeIndex = i;
2271 if (presentQueueNodeIndex == UINT32_MAX) {
2272 // If didn't find a queue that supports both graphics and present, then
2273 // find a separate present queue.
2275 for (i = 0; i < demo->queue_count; ++i) {
2276 if (supportsPresent[i] == VK_TRUE) {
2277 presentQueueNodeIndex = i;
2282 free(supportsPresent);
2284 // Generate error if could not find both a graphics and a present queue
2285 if (graphicsQueueNodeIndex == UINT32_MAX ||
2286 presentQueueNodeIndex == UINT32_MAX) {
2287 ERR_EXIT("Could not find a graphics and a present queue\n",
2288 "Swapchain Initialization Failure");
2291 // TODO: Add support for separate queues, including presentation,
2292 // synchronization, and appropriate tracking for QueueSubmit.
2293 // NOTE: While it is possible for an application to use a separate graphics
2294 // and a present queues, this demo program assumes it is only using
2296 if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
2297 ERR_EXIT("Could not find a common graphics and a present queue\n",
2298 "Swapchain Initialization Failure");
2301 demo->graphics_queue_node_index = graphicsQueueNodeIndex;
2303 demo_init_device(demo);
2305 vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 0,
2308 // Get the list of VkFormat's that are supported:
2309 uint32_t formatCount;
2310 err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
2311 &formatCount, NULL);
2313 VkSurfaceFormatKHR *surfFormats =
2314 (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
2315 err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
2316 &formatCount, surfFormats);
2318 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
2319 // the surface has no preferred format. Otherwise, at least one
2320 // supported format will be returned.
2321 if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
2322 demo->format = VK_FORMAT_B8G8R8A8_UNORM;
2324 assert(formatCount >= 1);
2325 demo->format = surfFormats[0].format;
2327 demo->color_space = surfFormats[0].colorSpace;
2332 // Get Memory information and properties
2333 vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
2337 registry_handle_global(void *data, struct wl_registry *registry,
2338 uint32_t name, const char *interface, uint32_t version) {
2339 struct demo *d = data;
2341 printf("%s, interface: %s\n", __func__, interface);
2343 if (strcmp(interface, "wl_compositor") == 0) {
2345 wl_registry_bind(registry, name,
2346 &wl_compositor_interface, 1);
2347 } else if (strcmp(interface, "wl_shm") == 0) {
2348 d->shm = wl_registry_bind(registry, name,
2349 &wl_shm_interface, 1);
2350 } else if (strcmp(interface, "wl_shell") == 0) {
2352 wl_registry_bind(registry, name,
2353 &wl_shell_interface, 1);
2358 registry_handle_global_remove(void *data, struct wl_registry *registry,
2362 static const struct wl_registry_listener registry_listener = {
2363 registry_handle_global,
2364 registry_handle_global_remove
2367 static void demo_init_connection(struct demo *demo) {
2369 demo->display = wl_display_connect(NULL);
2371 if (demo->display == NULL) {
2372 printf("Cannot find a compatible Vulkan installable client driver "
2373 "(ICD).\nExiting ...\n");
2378 demo->registry = wl_display_get_registry(demo->display);
2379 wl_registry_add_listener(demo->registry, ®istry_listener, demo);
2380 wl_display_dispatch(demo->display);
2384 static void demo_init(struct demo *demo, const int argc, const char *argv[])
2388 memset(demo, 0, sizeof(*demo));
2389 demo->frameCount = INT32_MAX;
2391 for (i = 1; i < argc; i++) {
2392 if (strcmp(argv[i], "--use_staging") == 0) {
2393 demo->use_staging_buffer = true;
2396 if (strcmp(argv[i], "--break") == 0) {
2397 demo->use_break = true;
2400 if (strcmp(argv[i], "--validate") == 0) {
2401 demo->validate = true;
2404 if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX &&
2405 i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 &&
2406 demo->frameCount >= 0) {
2411 fprintf(stderr, "Usage:\n %s [--use_staging] [--validate] [--break] "
2412 "[--c <framecount>]\n",
2418 demo_init_connection(demo);
2422 demo->height = 2560;
2423 demo->depthStencil = 1.0;
2424 demo->depthIncrement = -0.01f;
2427 static void demo_cleanup(struct demo *demo) {
2430 demo->prepared = false;
2432 for (i = 0; i < demo->swapchainImageCount; i++) {
2433 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2435 free(demo->framebuffers);
2436 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2438 if (demo->setup_cmd) {
2439 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2441 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2442 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2444 vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2445 vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2446 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2447 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2449 vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2450 vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2452 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2453 vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2454 vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2455 vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2456 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2459 for (i = 0; i < demo->swapchainImageCount; i++) {
2460 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2463 vkDestroyImageView(demo->device, demo->depth.view, NULL);
2464 vkDestroyImage(demo->device, demo->depth.image, NULL);
2465 vkFreeMemory(demo->device, demo->depth.mem, NULL);
2467 demo->fpDestroySwapchainKHR(demo->device, demo->swapchain, NULL);
2468 free(demo->buffers);
2470 vkDestroyDevice(demo->device, NULL);
2471 if (demo->validate) {
2472 demo->DestroyDebugReportCallback(demo->inst, demo->msg_callback, NULL);
2474 vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
2475 vkDestroyInstance(demo->inst, NULL);
2477 free(demo->queue_props);
2480 static void demo_resize(struct demo *demo) {
2483 // Don't react to resize until after first initialization.
2484 if (!demo->prepared) {
2487 // In order to properly resize the window, we must re-create the swapchain
2488 // AND redo the command buffers, etc.
2490 // First, perform part of the demo_cleanup() function:
2491 demo->prepared = false;
2493 for (i = 0; i < demo->swapchainImageCount; i++) {
2494 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2496 free(demo->framebuffers);
2497 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2499 if (demo->setup_cmd) {
2500 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2502 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2503 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2505 vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2506 vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2507 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2508 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2510 vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2511 vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2513 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2514 vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2515 vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2516 vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2517 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2520 for (i = 0; i < demo->swapchainImageCount; i++) {
2521 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2524 vkDestroyImageView(demo->device, demo->depth.view, NULL);
2525 vkDestroyImage(demo->device, demo->depth.image, NULL);
2526 vkFreeMemory(demo->device, demo->depth.mem, NULL);
2528 free(demo->buffers);
2530 // Second, re-perform the demo_prepare() function, which will re-create the
2536 // Include header required for parsing the command line options.
2537 #include <shellapi.h>
2539 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
2540 LPSTR pCmdLine, int nCmdShow) {
2542 bool done; // flag saying when app is complete
2546 // Use the CommandLine functions to get the command line arguments.
2547 // Unfortunately, Microsoft outputs
2548 // this information as wide characters for Unicode, and we simply want the
2549 // Ascii version to be compatible
2550 // with the non-Windows side. So, we have to convert the information to
2551 // Ascii character strings.
2552 LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc);
2553 if (NULL == commandLineArgs) {
2558 argv = (char **)malloc(sizeof(char *) * argc);
2562 for (int iii = 0; iii < argc; iii++) {
2563 size_t wideCharLen = wcslen(commandLineArgs[iii]);
2564 size_t numConverted = 0;
2566 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1));
2567 if (argv[iii] != NULL) {
2568 wcstombs_s(&numConverted, argv[iii], wideCharLen + 1,
2569 commandLineArgs[iii], wideCharLen + 1);
2577 demo_init(&demo, argc, argv);
2579 // Free up the items we had to allocate for the command line arguments.
2580 if (argc > 0 && argv != NULL) {
2581 for (int iii = 0; iii < argc; iii++) {
2582 if (argv[iii] != NULL) {
2589 demo.connection = hInstance;
2590 strncpy(demo.name, "tri", APP_NAME_STR_LEN);
2591 demo_create_window(&demo);
2592 demo_init_vk_swapchain(&demo);
2594 demo_prepare(&demo);
2596 done = false; // initialize loop condition variable
2597 /* main message loop*/
2599 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
2600 if (msg.message == WM_QUIT) // check for a quit message
2602 done = true; // if found, quit app
2604 /* Translate and dispatch to event queue*/
2605 TranslateMessage(&msg);
2606 DispatchMessage(&msg);
2608 RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT);
2611 demo_cleanup(&demo);
2613 return (int)msg.wParam;
2616 int main(const int argc, const char *argv[]) {
2619 demo_init(&demo, argc, argv);
2620 demo_create_window(&demo);
2621 demo_init_vk_swapchain(&demo);
2623 demo_prepare(&demo);
2626 demo_cleanup(&demo);
2628 return validation_error;