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 snprintf(message, sizeof(message), "ERROR: [%s] Code %d : %s",
132 pLayerPrefix, msgCode, pMsg);
133 } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
134 snprintf(message, sizeof(message), "WARNING: [%s] Code %d : %s",
135 pLayerPrefix, msgCode, pMsg);
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 = 0,
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)
1751 handle_ping(void *data, struct wl_shell_surface *shell_surface,
1753 printf("%s\n", __func__);
1754 wl_shell_surface_pong(shell_surface, serial);
1758 handle_configure(void *data, struct wl_shell_surface *shell_surface,
1759 uint32_t edges, int32_t width, int32_t height) {
1760 printf("%s, (%d, %d)\n", __func__, width, height);
1764 handle_popup_done(void *data, struct wl_shell_surface *shell_surface) {
1767 static const struct wl_shell_surface_listener shell_surface_listener = {
1773 static void demo_create_window(struct demo *demo) {
1774 demo->wl_surface = wl_compositor_create_surface(demo->compositor);
1776 demo->shell_surface = wl_shell_get_shell_surface(demo->shell, demo->wl_surface);
1778 if (demo->shell_surface) {
1779 wl_shell_surface_add_listener(demo->shell_surface,
1780 &shell_surface_listener, demo);
1781 wl_shell_surface_set_toplevel(demo->shell_surface);
1784 wl_surface_set_user_data(demo->wl_surface, demo);
1785 wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME);
1790 * Return 1 (true) if all layer names specified in check_names
1791 * can be found in given layer properties.
1793 static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
1794 uint32_t layer_count,
1795 VkLayerProperties *layers) {
1797 for (i = 0; i < check_count; i++) {
1799 for (j = 0; j < layer_count; j++) {
1800 if (!strcmp(check_names[i], layers[j].layerName)) {
1806 fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
1813 static void demo_init_vk(struct demo *demo) {
1815 uint32_t instance_extension_count = 0;
1816 uint32_t instance_layer_count = 0;
1817 uint32_t device_validation_layer_count = 0;
1818 char **instance_validation_layers = NULL;
1820 demo->enabled_extension_count = 0;
1821 demo->enabled_layer_count = 0;
1823 char *instance_validation_layers_alt1[] = {
1824 "VK_LAYER_LUNARG_standard_validation"
1827 char *instance_validation_layers_alt2[] = {
1828 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation",
1829 "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker",
1830 "VK_LAYER_LUNARG_image", "VK_LAYER_LUNARG_core_validation",
1831 "VK_LAYER_LUNARG_swapchain", "VK_LAYER_GOOGLE_unique_objects"
1834 /* Look for validation layers */
1835 VkBool32 validation_found = 0;
1836 if (demo->validate) {
1838 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
1841 instance_validation_layers = instance_validation_layers_alt1;
1842 if (instance_layer_count > 0) {
1843 VkLayerProperties *instance_layers =
1844 malloc(sizeof (VkLayerProperties) * instance_layer_count);
1845 err = vkEnumerateInstanceLayerProperties(&instance_layer_count,
1850 validation_found = demo_check_layers(
1851 ARRAY_SIZE(instance_validation_layers_alt1),
1852 instance_validation_layers, instance_layer_count,
1854 if (validation_found) {
1855 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
1856 demo->device_validation_layers[0] = "VK_LAYER_LUNARG_standard_validation";
1857 device_validation_layer_count = 1;
1859 // use alternative set of validation layers
1860 instance_validation_layers = instance_validation_layers_alt2;
1861 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
1862 validation_found = demo_check_layers(
1863 ARRAY_SIZE(instance_validation_layers_alt2),
1864 instance_validation_layers, instance_layer_count,
1866 device_validation_layer_count =
1867 ARRAY_SIZE(instance_validation_layers_alt2);
1868 for (i = 0; i < device_validation_layer_count; i++) {
1869 demo->device_validation_layers[i] =
1870 instance_validation_layers[i];
1873 free(instance_layers);
1876 if (!validation_found) {
1877 ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find"
1878 "required validation layer.\n\n"
1879 "Please look at the Getting Started guide for additional "
1881 "vkCreateInstance Failure");
1885 /* Look for instance extensions */
1886 VkBool32 surfaceExtFound = 0;
1887 VkBool32 platformSurfaceExtFound = 0;
1888 memset(demo->extension_names, 0, sizeof(demo->extension_names));
1890 err = vkEnumerateInstanceExtensionProperties(
1891 NULL, &instance_extension_count, NULL);
1894 if (instance_extension_count > 0) {
1896 VkExtensionProperties *instance_extensions =
1897 malloc(sizeof(VkExtensionProperties) * instance_extension_count);
1898 err = vkEnumerateInstanceExtensionProperties(
1899 NULL, &instance_extension_count, instance_extensions);
1901 for (i = 0; i < instance_extension_count; i++) {
1902 if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME,
1903 instance_extensions[i].extensionName)) {
1904 surfaceExtFound = 1;
1905 demo->extension_names[demo->enabled_extension_count++] =
1906 VK_KHR_SURFACE_EXTENSION_NAME;
1909 if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
1910 instance_extensions[i].extensionName)) {
1911 platformSurfaceExtFound = 1;
1912 demo->extension_names[demo->enabled_extension_count++] =
1913 VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
1916 if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
1917 instance_extensions[i].extensionName)) {
1918 platformSurfaceExtFound = 1;
1919 demo->extension_names[demo->enabled_extension_count++] =
1920 VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
1923 if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
1924 instance_extensions[i].extensionName)) {
1925 if (demo->validate) {
1926 demo->extension_names[demo->enabled_extension_count++] =
1927 VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
1930 assert(demo->enabled_extension_count < 64);
1933 free(instance_extensions);
1936 if (!surfaceExtFound) {
1937 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1938 "the " VK_KHR_SURFACE_EXTENSION_NAME
1939 " extension.\n\nDo you have a compatible "
1940 "Vulkan installable client driver (ICD) installed?\nPlease "
1941 "look at the Getting Started guide for additional "
1943 "vkCreateInstance Failure");
1945 if (!platformSurfaceExtFound) {
1947 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1948 "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME
1949 " extension.\n\nDo you have a compatible "
1950 "Vulkan installable client driver (ICD) installed?\nPlease "
1951 "look at the Getting Started guide for additional "
1953 "vkCreateInstance Failure");
1955 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1956 "the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
1957 " extension.\n\nDo you have a compatible "
1958 "Vulkan installable client driver (ICD) installed?\nPlease "
1959 "look at the Getting Started guide for additional "
1961 "vkCreateInstance Failure");
1964 const VkApplicationInfo app = {
1965 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
1967 .pApplicationName = APP_SHORT_NAME,
1968 .applicationVersion = 0,
1969 .pEngineName = APP_SHORT_NAME,
1971 .apiVersion = VK_API_VERSION_1_0,
1973 VkInstanceCreateInfo inst_info = {
1974 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
1976 .pApplicationInfo = &app,
1977 .enabledLayerCount = demo->enabled_layer_count,
1978 .ppEnabledLayerNames = (const char *const *)instance_validation_layers,
1979 .enabledExtensionCount = demo->enabled_extension_count,
1980 .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
1985 err = vkCreateInstance(&inst_info, NULL, &demo->inst);
1986 if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
1987 ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
1988 "(ICD).\n\nPlease look at the Getting Started guide for "
1989 "additional information.\n",
1990 "vkCreateInstance Failure");
1991 } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
1992 ERR_EXIT("Cannot find a specified extension library"
1993 ".\nMake sure your layers path is set appropriately\n",
1994 "vkCreateInstance Failure");
1996 ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
1997 "installable client driver (ICD) installed?\nPlease look at "
1998 "the Getting Started guide for additional information.\n",
1999 "vkCreateInstance Failure");
2002 /* Make initial call to query gpu_count, then second call for gpu info*/
2003 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
2004 assert(!err && gpu_count > 0);
2006 if (gpu_count > 0) {
2007 VkPhysicalDevice *physical_devices =
2008 malloc(sizeof(VkPhysicalDevice) * gpu_count);
2009 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count,
2012 /* For tri demo we just grab the first physical device */
2013 demo->gpu = physical_devices[0];
2014 free(physical_devices);
2016 ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible devices."
2017 "\n\nDo you have a compatible Vulkan installable client"
2018 " driver (ICD) installed?\nPlease look at the Getting Started"
2019 " guide for additional information.\n",
2020 "vkEnumeratePhysicalDevices Failure");
2023 /* Look for validation layers */
2024 if (demo->validate) {
2025 validation_found = 0;
2026 demo->enabled_layer_count = 0;
2027 uint32_t device_layer_count = 0;
2029 vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, NULL);
2032 if (device_layer_count > 0) {
2033 VkLayerProperties *device_layers =
2034 malloc(sizeof (VkLayerProperties) * device_layer_count);
2035 err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count,
2040 validation_found = demo_check_layers(device_validation_layer_count,
2041 demo->device_validation_layers,
2044 demo->enabled_layer_count = device_validation_layer_count;
2046 free(device_layers);
2049 if (!validation_found) {
2050 ERR_EXIT("vkEnumerateDeviceLayerProperties failed to find "
2051 "a required validation layer.\n\n"
2052 "Please look at the Getting Started guide for additional "
2054 "vkCreateDevice Failure");
2058 /* Look for device extensions */
2059 uint32_t device_extension_count = 0;
2060 VkBool32 swapchainExtFound = 0;
2061 demo->enabled_extension_count = 0;
2062 memset(demo->extension_names, 0, sizeof(demo->extension_names));
2064 err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL,
2065 &device_extension_count, NULL);
2068 if (device_extension_count > 0) {
2070 VkExtensionProperties *device_extensions =
2071 malloc(sizeof(VkExtensionProperties) * device_extension_count);
2072 err = vkEnumerateDeviceExtensionProperties(
2073 demo->gpu, NULL, &device_extension_count, device_extensions);
2076 for (i = 0; i < device_extension_count; i++) {
2077 if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,
2078 device_extensions[i].extensionName)) {
2079 swapchainExtFound = 1;
2080 demo->extension_names[demo->enabled_extension_count++] =
2081 VK_KHR_SWAPCHAIN_EXTENSION_NAME;
2083 assert(demo->enabled_extension_count < 64);
2086 free(device_extensions);
2089 if (!swapchainExtFound) {
2090 ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find "
2091 "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME
2092 " extension.\n\nDo you have a compatible "
2093 "Vulkan installable client driver (ICD) installed?\nPlease "
2094 "look at the Getting Started guide for additional "
2096 "vkCreateInstance Failure");
2099 if (demo->validate) {
2100 demo->CreateDebugReportCallback =
2101 (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(
2102 demo->inst, "vkCreateDebugReportCallbackEXT");
2103 demo->DestroyDebugReportCallback =
2104 (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(
2105 demo->inst, "vkDestroyDebugReportCallbackEXT");
2106 if (!demo->CreateDebugReportCallback) {
2108 "GetProcAddr: Unable to find vkCreateDebugReportCallbackEXT\n",
2109 "vkGetProcAddr Failure");
2111 if (!demo->DestroyDebugReportCallback) {
2113 "GetProcAddr: Unable to find vkDestroyDebugReportCallbackEXT\n",
2114 "vkGetProcAddr Failure");
2116 demo->DebugReportMessage =
2117 (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(
2118 demo->inst, "vkDebugReportMessageEXT");
2119 if (!demo->DebugReportMessage) {
2120 ERR_EXIT("GetProcAddr: Unable to find vkDebugReportMessageEXT\n",
2121 "vkGetProcAddr Failure");
2124 VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
2125 dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
2126 dbgCreateInfo.flags =
2127 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
2128 dbgCreateInfo.pfnCallback = demo->use_break ? BreakCallback : dbgFunc;
2129 dbgCreateInfo.pUserData = NULL;
2130 dbgCreateInfo.pNext = NULL;
2131 err = demo->CreateDebugReportCallback(demo->inst, &dbgCreateInfo, NULL,
2132 &demo->msg_callback);
2136 case VK_ERROR_OUT_OF_HOST_MEMORY:
2137 ERR_EXIT("CreateDebugReportCallback: out of host memory\n",
2138 "CreateDebugReportCallback Failure");
2141 ERR_EXIT("CreateDebugReportCallback: unknown failure\n",
2142 "CreateDebugReportCallback Failure");
2147 // Having these GIPA queries of device extension entry points both
2148 // BEFORE and AFTER vkCreateDevice is a good test for the loader
2149 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceCapabilitiesKHR);
2150 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR);
2151 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR);
2152 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR);
2153 GET_INSTANCE_PROC_ADDR(demo->inst, CreateSwapchainKHR);
2154 GET_INSTANCE_PROC_ADDR(demo->inst, DestroySwapchainKHR);
2155 GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR);
2156 GET_INSTANCE_PROC_ADDR(demo->inst, AcquireNextImageKHR);
2157 GET_INSTANCE_PROC_ADDR(demo->inst, QueuePresentKHR);
2159 vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
2161 // Query with NULL data to get count
2162 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
2165 demo->queue_props = (VkQueueFamilyProperties *)malloc(
2166 demo->queue_count * sizeof(VkQueueFamilyProperties));
2167 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
2169 assert(demo->queue_count >= 1);
2171 VkPhysicalDeviceFeatures features;
2172 vkGetPhysicalDeviceFeatures(demo->gpu, &features);
2174 #if 0 /* Temporarily disable checking shader clip distance feature. */
2175 if (!features.shaderClipDistance) {
2176 ERR_EXIT("Required device feature `shaderClipDistance` not supported\n",
2177 "GetPhysicalDeviceFeatures failure");
2181 // Graphics queue and MemMgr queue can be separate.
2182 // TODO: Add support for separate queues, including synchronization,
2183 // and appropriate tracking for QueueSubmit
2186 static void demo_init_device(struct demo *demo) {
2187 VkResult U_ASSERT_ONLY err;
2189 float queue_priorities[1] = {0.0};
2190 const VkDeviceQueueCreateInfo queue = {
2191 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
2193 .queueFamilyIndex = demo->graphics_queue_node_index,
2195 .pQueuePriorities = queue_priorities};
2197 VkPhysicalDeviceFeatures features = {
2198 .shaderClipDistance = VK_TRUE,
2201 VkDeviceCreateInfo device = {
2202 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
2204 .queueCreateInfoCount = 1,
2205 .pQueueCreateInfos = &queue,
2206 .enabledLayerCount = demo->enabled_layer_count,
2207 .ppEnabledLayerNames =
2208 (const char *const *)((demo->validate)
2209 ? demo->device_validation_layers
2211 .enabledExtensionCount = demo->enabled_extension_count,
2212 .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
2213 .pEnabledFeatures = &features,
2216 err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
2220 static void demo_init_vk_swapchain(struct demo *demo) {
2221 VkResult U_ASSERT_ONLY err;
2224 // Create a WSI surface for the window:
2226 VkWin32SurfaceCreateInfoKHR createInfo;
2227 createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
2228 createInfo.pNext = NULL;
2229 createInfo.flags = 0;
2230 createInfo.hinstance = demo->connection;
2231 createInfo.hwnd = demo->window;
2234 vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
2237 VkWaylandSurfaceCreateInfoKHR createInfo;
2238 createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
2239 createInfo.pNext = NULL;
2240 createInfo.flags = 0;
2241 createInfo.display = demo->display;
2242 createInfo.surface = demo->wl_surface;
2244 err = vkCreateWaylandSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
2247 // Iterate over each queue to learn whether it supports presenting:
2248 VkBool32 *supportsPresent =
2249 (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32));
2250 for (i = 0; i < demo->queue_count; i++) {
2251 demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface,
2252 &supportsPresent[i]);
2255 // Search for a graphics and a present queue in the array of queue
2256 // families, try to find one that supports both
2257 uint32_t graphicsQueueNodeIndex = UINT32_MAX;
2258 uint32_t presentQueueNodeIndex = UINT32_MAX;
2259 for (i = 0; i < demo->queue_count; i++) {
2260 if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
2261 if (graphicsQueueNodeIndex == UINT32_MAX) {
2262 graphicsQueueNodeIndex = i;
2265 if (supportsPresent[i] == VK_TRUE) {
2266 graphicsQueueNodeIndex = i;
2267 presentQueueNodeIndex = i;
2272 if (presentQueueNodeIndex == UINT32_MAX) {
2273 // If didn't find a queue that supports both graphics and present, then
2274 // find a separate present queue.
2276 for (i = 0; i < demo->queue_count; ++i) {
2277 if (supportsPresent[i] == VK_TRUE) {
2278 presentQueueNodeIndex = i;
2283 free(supportsPresent);
2285 // Generate error if could not find both a graphics and a present queue
2286 if (graphicsQueueNodeIndex == UINT32_MAX ||
2287 presentQueueNodeIndex == UINT32_MAX) {
2288 ERR_EXIT("Could not find a graphics and a present queue\n",
2289 "Swapchain Initialization Failure");
2292 // TODO: Add support for separate queues, including presentation,
2293 // synchronization, and appropriate tracking for QueueSubmit.
2294 // NOTE: While it is possible for an application to use a separate graphics
2295 // and a present queues, this demo program assumes it is only using
2297 if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
2298 ERR_EXIT("Could not find a common graphics and a present queue\n",
2299 "Swapchain Initialization Failure");
2302 demo->graphics_queue_node_index = graphicsQueueNodeIndex;
2304 demo_init_device(demo);
2306 vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 0,
2309 // Get the list of VkFormat's that are supported:
2310 uint32_t formatCount;
2311 err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
2312 &formatCount, NULL);
2314 VkSurfaceFormatKHR *surfFormats =
2315 (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
2316 err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
2317 &formatCount, surfFormats);
2319 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
2320 // the surface has no preferred format. Otherwise, at least one
2321 // supported format will be returned.
2322 if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
2323 demo->format = VK_FORMAT_B8G8R8A8_UNORM;
2325 assert(formatCount >= 1);
2326 demo->format = surfFormats[0].format;
2328 demo->color_space = surfFormats[0].colorSpace;
2333 // Get Memory information and properties
2334 vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
2338 registry_handle_global(void *data, struct wl_registry *registry,
2339 uint32_t name, const char *interface, uint32_t version) {
2340 struct demo *d = data;
2342 printf("%s, interface: %s\n", __func__, interface);
2344 if (strcmp(interface, "wl_compositor") == 0) {
2346 wl_registry_bind(registry, name,
2347 &wl_compositor_interface, 1);
2348 } else if (strcmp(interface, "wl_shm") == 0) {
2349 d->shm = wl_registry_bind(registry, name,
2350 &wl_shm_interface, 1);
2351 } else if (strcmp(interface, "wl_shell") == 0) {
2353 wl_registry_bind(registry, name,
2354 &wl_shell_interface, 1);
2359 registry_handle_global_remove(void *data, struct wl_registry *registry,
2363 static const struct wl_registry_listener registry_listener = {
2364 registry_handle_global,
2365 registry_handle_global_remove
2368 static void demo_init_connection(struct demo *demo) {
2370 demo->display = wl_display_connect(NULL);
2372 if (demo->display == NULL) {
2373 printf("Cannot find a compatible Vulkan installable client driver "
2374 "(ICD).\nExiting ...\n");
2379 demo->registry = wl_display_get_registry(demo->display);
2380 wl_registry_add_listener(demo->registry, ®istry_listener, demo);
2381 wl_display_dispatch(demo->display);
2385 static void demo_init(struct demo *demo, const int argc, const char *argv[])
2389 memset(demo, 0, sizeof(*demo));
2390 demo->frameCount = INT32_MAX;
2392 for (i = 1; i < argc; i++) {
2393 if (strcmp(argv[i], "--use_staging") == 0) {
2394 demo->use_staging_buffer = true;
2397 if (strcmp(argv[i], "--break") == 0) {
2398 demo->use_break = true;
2401 if (strcmp(argv[i], "--validate") == 0) {
2402 demo->validate = true;
2405 if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX &&
2406 i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 &&
2407 demo->frameCount >= 0) {
2412 fprintf(stderr, "Usage:\n %s [--use_staging] [--validate] [--break] "
2413 "[--c <framecount>]\n",
2419 demo_init_connection(demo);
2423 demo->height = 2560;
2424 demo->depthStencil = 1.0;
2425 demo->depthIncrement = -0.01f;
2428 static void demo_cleanup(struct demo *demo) {
2431 demo->prepared = false;
2433 for (i = 0; i < demo->swapchainImageCount; i++) {
2434 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2436 free(demo->framebuffers);
2437 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2439 if (demo->setup_cmd) {
2440 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2442 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2443 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2445 vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2446 vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2447 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2448 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2450 vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2451 vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2453 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2454 vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2455 vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2456 vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2457 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2460 for (i = 0; i < demo->swapchainImageCount; i++) {
2461 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2464 vkDestroyImageView(demo->device, demo->depth.view, NULL);
2465 vkDestroyImage(demo->device, demo->depth.image, NULL);
2466 vkFreeMemory(demo->device, demo->depth.mem, NULL);
2468 demo->fpDestroySwapchainKHR(demo->device, demo->swapchain, NULL);
2469 free(demo->buffers);
2471 vkDestroyDevice(demo->device, NULL);
2472 if (demo->validate) {
2473 demo->DestroyDebugReportCallback(demo->inst, demo->msg_callback, NULL);
2475 vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
2476 vkDestroyInstance(demo->inst, NULL);
2478 free(demo->queue_props);
2481 static void demo_resize(struct demo *demo) {
2484 // Don't react to resize until after first initialization.
2485 if (!demo->prepared) {
2488 // In order to properly resize the window, we must re-create the swapchain
2489 // AND redo the command buffers, etc.
2491 // First, perform part of the demo_cleanup() function:
2492 demo->prepared = false;
2494 for (i = 0; i < demo->swapchainImageCount; i++) {
2495 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2497 free(demo->framebuffers);
2498 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2500 if (demo->setup_cmd) {
2501 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2503 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2504 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2506 vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2507 vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2508 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2509 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2511 vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2512 vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2514 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2515 vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2516 vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2517 vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2518 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2521 for (i = 0; i < demo->swapchainImageCount; i++) {
2522 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2525 vkDestroyImageView(demo->device, demo->depth.view, NULL);
2526 vkDestroyImage(demo->device, demo->depth.image, NULL);
2527 vkFreeMemory(demo->device, demo->depth.mem, NULL);
2529 free(demo->buffers);
2531 // Second, re-perform the demo_prepare() function, which will re-create the
2537 // Include header required for parsing the command line options.
2538 #include <shellapi.h>
2540 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
2541 LPSTR pCmdLine, int nCmdShow) {
2543 bool done; // flag saying when app is complete
2547 // Use the CommandLine functions to get the command line arguments.
2548 // Unfortunately, Microsoft outputs
2549 // this information as wide characters for Unicode, and we simply want the
2550 // Ascii version to be compatible
2551 // with the non-Windows side. So, we have to convert the information to
2552 // Ascii character strings.
2553 LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc);
2554 if (NULL == commandLineArgs) {
2559 argv = (char **)malloc(sizeof(char *) * argc);
2563 for (int iii = 0; iii < argc; iii++) {
2564 size_t wideCharLen = wcslen(commandLineArgs[iii]);
2565 size_t numConverted = 0;
2567 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1));
2568 if (argv[iii] != NULL) {
2569 wcstombs_s(&numConverted, argv[iii], wideCharLen + 1,
2570 commandLineArgs[iii], wideCharLen + 1);
2578 demo_init(&demo, argc, argv);
2580 // Free up the items we had to allocate for the command line arguments.
2581 if (argc > 0 && argv != NULL) {
2582 for (int iii = 0; iii < argc; iii++) {
2583 if (argv[iii] != NULL) {
2590 demo.connection = hInstance;
2591 strncpy(demo.name, "tri", APP_NAME_STR_LEN);
2592 demo_create_window(&demo);
2593 demo_init_vk_swapchain(&demo);
2595 demo_prepare(&demo);
2597 done = false; // initialize loop condition variable
2598 /* main message loop*/
2600 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
2601 if (msg.message == WM_QUIT) // check for a quit message
2603 done = true; // if found, quit app
2605 /* Translate and dispatch to event queue*/
2606 TranslateMessage(&msg);
2607 DispatchMessage(&msg);
2609 RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT);
2612 demo_cleanup(&demo);
2614 return (int)msg.wParam;
2617 int main(const int argc, const char *argv[]) {
2620 demo_init(&demo, argc, argv);
2621 demo_create_window(&demo);
2622 demo_init_vk_swapchain(&demo);
2624 demo_prepare(&demo);
2627 demo_cleanup(&demo);
2629 return validation_error;