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);
142 MessageBox(NULL, message, "Alert", MB_OK);
144 printf("%s\n", message);
150 * false indicates that layer should not bail-out of an
151 * API call that had validation failures. This may mean that the
152 * app dies inside the driver due to invalid parameter(s).
153 * That's what would happen without validation layers, so we'll
154 * keep that behavior here.
159 VKAPI_ATTR VkBool32 VKAPI_CALL
160 BreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
161 uint64_t srcObject, size_t location, int32_t msgCode,
162 const char *pLayerPrefix, const char *pMsg,
173 typedef struct _SwapchainBuffers {
181 #define APP_NAME_STR_LEN 80
182 HINSTANCE connection; // hInstance - Windows Instance
183 char name[APP_NAME_STR_LEN]; // Name to put on the window/icon
184 HWND window; // hWnd - window handle
186 struct wl_display *display;
187 struct wl_registry *registry;
188 struct wl_compositor *compositor;
189 struct wl_seat *seat;
190 struct wl_surface *wl_surface;
192 struct wl_shell *shell;
193 struct wl_shell_surface *shell_surface;
195 VkSurfaceKHR surface;
197 bool use_staging_buffer;
200 VkPhysicalDevice gpu;
203 VkPhysicalDeviceProperties gpu_props;
204 VkQueueFamilyProperties *queue_props;
205 uint32_t graphics_queue_node_index;
207 uint32_t enabled_extension_count;
208 uint32_t enabled_layer_count;
209 char *extension_names[64];
210 char *device_validation_layers[64];
214 VkColorSpaceKHR color_space;
216 PFN_vkGetPhysicalDeviceSurfaceSupportKHR
217 fpGetPhysicalDeviceSurfaceSupportKHR;
218 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
219 fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
220 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR
221 fpGetPhysicalDeviceSurfaceFormatsKHR;
222 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR
223 fpGetPhysicalDeviceSurfacePresentModesKHR;
224 PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
225 PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
226 PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
227 PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
228 PFN_vkQueuePresentKHR fpQueuePresentKHR;
229 uint32_t swapchainImageCount;
230 VkSwapchainKHR swapchain;
231 SwapchainBuffers *buffers;
233 VkCommandPool cmd_pool;
243 struct texture_object textures[DEMO_TEXTURE_COUNT];
249 VkPipelineVertexInputStateCreateInfo vi;
250 VkVertexInputBindingDescription vi_bindings[1];
251 VkVertexInputAttributeDescription vi_attrs[2];
254 VkCommandBuffer setup_cmd; // Command Buffer for initialization commands
255 VkCommandBuffer draw_cmd; // Command Buffer for drawing commands
256 VkPipelineLayout pipeline_layout;
257 VkDescriptorSetLayout desc_layout;
258 VkPipelineCache pipelineCache;
259 VkRenderPass render_pass;
262 VkShaderModule vert_shader_module;
263 VkShaderModule frag_shader_module;
265 VkDescriptorPool desc_pool;
266 VkDescriptorSet desc_set;
268 VkFramebuffer *framebuffers;
270 VkPhysicalDeviceMemoryProperties memory_properties;
276 PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback;
277 PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback;
278 VkDebugReportCallbackEXT msg_callback;
279 PFN_vkDebugReportMessageEXT DebugReportMessage;
282 float depthIncrement;
285 uint32_t current_buffer;
286 uint32_t queue_count;
289 // Forward declaration:
290 static void demo_resize(struct demo *demo);
292 static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits,
293 VkFlags requirements_mask,
294 uint32_t *typeIndex) {
297 // Search memtypes to find first index with those properties
298 for (i = 0; i < 32; i++) {
299 if ((typeBits & 1) == 1) {
300 // Type is available, does it match user properties?
301 if ((demo->memory_properties.memoryTypes[i].propertyFlags &
302 requirements_mask) == requirements_mask) {
309 // No memory types matched, return failure
313 static void demo_flush_init_cmd(struct demo *demo) {
314 VkResult U_ASSERT_ONLY err;
316 if (demo->setup_cmd == VK_NULL_HANDLE)
319 err = vkEndCommandBuffer(demo->setup_cmd);
322 const VkCommandBuffer cmd_bufs[] = {demo->setup_cmd};
323 VkFence nullFence = {VK_NULL_HANDLE};
324 VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
326 .waitSemaphoreCount = 0,
327 .pWaitSemaphores = NULL,
328 .pWaitDstStageMask = NULL,
329 .commandBufferCount = 1,
330 .pCommandBuffers = cmd_bufs,
331 .signalSemaphoreCount = 0,
332 .pSignalSemaphores = NULL};
334 err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence);
337 err = vkQueueWaitIdle(demo->queue);
340 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, cmd_bufs);
341 demo->setup_cmd = VK_NULL_HANDLE;
344 static void demo_set_image_layout(struct demo *demo, VkImage image,
345 VkImageAspectFlags aspectMask,
346 VkImageLayout old_image_layout,
347 VkImageLayout new_image_layout,
348 VkAccessFlagBits srcAccessMask) {
350 VkResult U_ASSERT_ONLY err;
352 if (demo->setup_cmd == VK_NULL_HANDLE) {
353 const VkCommandBufferAllocateInfo cmd = {
354 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
356 .commandPool = demo->cmd_pool,
357 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
358 .commandBufferCount = 1,
361 err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->setup_cmd);
364 VkCommandBufferInheritanceInfo cmd_buf_hinfo = {
365 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
367 .renderPass = VK_NULL_HANDLE,
369 .framebuffer = VK_NULL_HANDLE,
370 .occlusionQueryEnable = VK_FALSE,
372 .pipelineStatistics = 0,
374 VkCommandBufferBeginInfo cmd_buf_info = {
375 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
378 .pInheritanceInfo = &cmd_buf_hinfo,
380 err = vkBeginCommandBuffer(demo->setup_cmd, &cmd_buf_info);
384 VkImageMemoryBarrier image_memory_barrier = {
385 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
387 .srcAccessMask = srcAccessMask,
389 .oldLayout = old_image_layout,
390 .newLayout = new_image_layout,
392 .subresourceRange = {aspectMask, 0, 1, 0, 1}};
394 if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
395 /* Make sure anything that was copying from this image has completed */
396 image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
399 if (new_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
400 image_memory_barrier.dstAccessMask =
401 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
404 if (new_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
405 image_memory_barrier.dstAccessMask =
406 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
409 if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
410 /* Make sure any Copy or CPU writes to image are flushed */
411 image_memory_barrier.dstAccessMask =
412 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
415 VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier;
417 VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
418 VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
420 vkCmdPipelineBarrier(demo->setup_cmd, src_stages, dest_stages, 0, 0, NULL,
421 0, NULL, 1, pmemory_barrier);
424 static void demo_draw_build_cmd(struct demo *demo) {
425 const VkCommandBufferInheritanceInfo cmd_buf_hinfo = {
426 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
428 .renderPass = VK_NULL_HANDLE,
430 .framebuffer = VK_NULL_HANDLE,
431 .occlusionQueryEnable = VK_FALSE,
433 .pipelineStatistics = 0,
435 const VkCommandBufferBeginInfo cmd_buf_info = {
436 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
439 .pInheritanceInfo = &cmd_buf_hinfo,
441 const VkClearValue clear_values[2] = {
442 [0] = {.color.float32 = {0.2f, 0.2f, 0.2f, 0.2f}},
443 [1] = {.depthStencil = {demo->depthStencil, 0}},
445 const VkRenderPassBeginInfo rp_begin = {
446 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
448 .renderPass = demo->render_pass,
449 .framebuffer = demo->framebuffers[demo->current_buffer],
450 .renderArea.offset.x = 0,
451 .renderArea.offset.y = 0,
452 .renderArea.extent.width = demo->width,
453 .renderArea.extent.height = demo->height,
454 .clearValueCount = 2,
455 .pClearValues = clear_values,
457 VkResult U_ASSERT_ONLY err;
459 err = vkBeginCommandBuffer(demo->draw_cmd, &cmd_buf_info);
462 vkCmdBeginRenderPass(demo->draw_cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
463 vkCmdBindPipeline(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
465 vkCmdBindDescriptorSets(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
466 demo->pipeline_layout, 0, 1, &demo->desc_set, 0,
470 memset(&viewport, 0, sizeof(viewport));
471 viewport.height = (float)demo->height;
472 viewport.width = (float)demo->width;
473 viewport.minDepth = (float)0.0f;
474 viewport.maxDepth = (float)1.0f;
475 vkCmdSetViewport(demo->draw_cmd, 0, 1, &viewport);
478 memset(&scissor, 0, sizeof(scissor));
479 scissor.extent.width = demo->width;
480 scissor.extent.height = demo->height;
481 scissor.offset.x = 0;
482 scissor.offset.y = 0;
483 vkCmdSetScissor(demo->draw_cmd, 0, 1, &scissor);
485 VkDeviceSize offsets[1] = {0};
486 vkCmdBindVertexBuffers(demo->draw_cmd, VERTEX_BUFFER_BIND_ID, 1,
487 &demo->vertices.buf, offsets);
489 vkCmdDraw(demo->draw_cmd, 3, 1, 0, 0);
490 vkCmdEndRenderPass(demo->draw_cmd);
492 VkImageMemoryBarrier prePresentBarrier = {
493 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
495 .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
496 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
497 .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
498 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
499 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
500 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
501 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
503 prePresentBarrier.image = demo->buffers[demo->current_buffer].image;
504 VkImageMemoryBarrier *pmemory_barrier = &prePresentBarrier;
505 vkCmdPipelineBarrier(demo->draw_cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
506 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0,
507 NULL, 1, pmemory_barrier);
509 err = vkEndCommandBuffer(demo->draw_cmd);
513 static void demo_draw(struct demo *demo) {
514 VkResult U_ASSERT_ONLY err;
515 VkSemaphore presentCompleteSemaphore;
516 VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = {
517 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
522 err = vkCreateSemaphore(demo->device, &presentCompleteSemaphoreCreateInfo,
523 NULL, &presentCompleteSemaphore);
526 // Get the index of the next available swapchain image:
527 err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX,
528 presentCompleteSemaphore,
529 (VkFence)0, // TODO: Show use of fence
530 &demo->current_buffer);
531 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
532 // demo->swapchain is out of date (e.g. the window was resized) and
533 // must be recreated:
536 vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL);
538 } else if (err == VK_SUBOPTIMAL_KHR) {
539 // demo->swapchain is not as optimal as it could be, but the platform's
540 // presentation engine will still present the image correctly.
545 // Assume the command buffer has been run on current_buffer before so
546 // we need to set the image layout back to COLOR_ATTACHMENT_OPTIMAL
547 demo_set_image_layout(demo, demo->buffers[demo->current_buffer].image,
548 VK_IMAGE_ASPECT_COLOR_BIT,
549 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
550 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
552 demo_flush_init_cmd(demo);
554 // Wait for the present complete semaphore to be signaled to ensure
555 // that the image won't be rendered to until the presentation
556 // engine has fully released ownership to the application, and it is
557 // okay to render to the image.
559 // FIXME/TODO: DEAL WITH VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
560 demo_draw_build_cmd(demo);
561 VkFence nullFence = VK_NULL_HANDLE;
562 VkPipelineStageFlags pipe_stage_flags =
563 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
564 VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
566 .waitSemaphoreCount = 0,
567 .pWaitSemaphores = &presentCompleteSemaphore,
568 .pWaitDstStageMask = &pipe_stage_flags,
569 .commandBufferCount = 1,
570 .pCommandBuffers = &demo->draw_cmd,
571 .signalSemaphoreCount = 0,
572 .pSignalSemaphores = NULL};
574 err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence);
577 VkPresentInfoKHR present = {
578 .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
581 .pSwapchains = &demo->swapchain,
582 .pImageIndices = &demo->current_buffer,
585 // TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER?
586 err = demo->fpQueuePresentKHR(demo->queue, &present);
587 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
588 // demo->swapchain is out of date (e.g. the window was resized) and
589 // must be recreated:
591 } else if (err == VK_SUBOPTIMAL_KHR) {
592 // demo->swapchain is not as optimal as it could be, but the platform's
593 // presentation engine will still present the image correctly.
598 err = vkQueueWaitIdle(demo->queue);
599 assert(err == VK_SUCCESS);
601 vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL);
604 static void demo_prepare_buffers(struct demo *demo) {
605 VkResult U_ASSERT_ONLY err;
606 VkSwapchainKHR oldSwapchain = demo->swapchain;
608 // Check the surface capabilities and formats
609 VkSurfaceCapabilitiesKHR surfCapabilities;
610 err = demo->fpGetPhysicalDeviceSurfaceCapabilitiesKHR(
611 demo->gpu, demo->surface, &surfCapabilities);
614 uint32_t presentModeCount;
615 err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(
616 demo->gpu, demo->surface, &presentModeCount, NULL);
618 VkPresentModeKHR *presentModes =
619 (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
620 assert(presentModes);
621 err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(
622 demo->gpu, demo->surface, &presentModeCount, presentModes);
625 VkExtent2D swapchainExtent;
626 // width and height are either both -1, or both not -1.
627 if (surfCapabilities.currentExtent.width == (uint32_t)-1) {
628 // If the surface size is undefined, the size is set to
629 // the size of the images requested.
630 swapchainExtent.width = demo->width;
631 swapchainExtent.height = demo->height;
633 // If the surface size is defined, the swap chain size must match
634 swapchainExtent = surfCapabilities.currentExtent;
635 demo->width = surfCapabilities.currentExtent.width;
636 demo->height = surfCapabilities.currentExtent.height;
639 VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
641 // Determine the number of VkImage's to use in the swap chain (we desire to
642 // own only 1 image at a time, besides the images being displayed and
643 // queued for display):
644 uint32_t desiredNumberOfSwapchainImages =
645 surfCapabilities.minImageCount + 1;
646 if ((surfCapabilities.maxImageCount > 0) &&
647 (desiredNumberOfSwapchainImages > surfCapabilities.maxImageCount)) {
648 // Application must settle for fewer images than desired:
649 desiredNumberOfSwapchainImages = surfCapabilities.maxImageCount;
652 VkSurfaceTransformFlagsKHR preTransform;
653 if (surfCapabilities.supportedTransforms &
654 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
655 preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
657 preTransform = surfCapabilities.currentTransform;
660 const VkSwapchainCreateInfoKHR swapchain = {
661 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
663 .surface = demo->surface,
664 .minImageCount = desiredNumberOfSwapchainImages,
665 .imageFormat = demo->format,
666 .imageColorSpace = demo->color_space,
669 .width = swapchainExtent.width, .height = swapchainExtent.height,
671 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
672 .preTransform = preTransform,
673 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
674 .imageArrayLayers = 1,
675 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
676 .queueFamilyIndexCount = 0,
677 .pQueueFamilyIndices = NULL,
678 .presentMode = swapchainPresentMode,
679 .oldSwapchain = oldSwapchain,
684 err = demo->fpCreateSwapchainKHR(demo->device, &swapchain, NULL,
688 // If we just re-created an existing swapchain, we should destroy the old
689 // swapchain at this point.
690 // Note: destroying the swapchain also cleans up all its associated
691 // presentable images once the platform is done with them.
692 if (oldSwapchain != VK_NULL_HANDLE) {
693 demo->fpDestroySwapchainKHR(demo->device, oldSwapchain, NULL);
696 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
697 &demo->swapchainImageCount, NULL);
700 VkImage *swapchainImages =
701 (VkImage *)malloc(demo->swapchainImageCount * sizeof(VkImage));
702 assert(swapchainImages);
703 err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
704 &demo->swapchainImageCount,
708 demo->buffers = (SwapchainBuffers *)malloc(sizeof(SwapchainBuffers) *
709 demo->swapchainImageCount);
710 assert(demo->buffers);
712 for (i = 0; i < demo->swapchainImageCount; i++) {
713 VkImageViewCreateInfo color_attachment_view = {
714 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
716 .format = demo->format,
719 .r = VK_COMPONENT_SWIZZLE_R,
720 .g = VK_COMPONENT_SWIZZLE_G,
721 .b = VK_COMPONENT_SWIZZLE_B,
722 .a = VK_COMPONENT_SWIZZLE_A,
724 .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
729 .viewType = VK_IMAGE_VIEW_TYPE_2D,
733 demo->buffers[i].image = swapchainImages[i];
735 // Render loop will expect image to have been used before and in
736 // VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
737 // layout and will change to COLOR_ATTACHMENT_OPTIMAL, so init the image
739 demo_set_image_layout(
740 demo, demo->buffers[i].image, VK_IMAGE_ASPECT_COLOR_BIT,
741 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
744 color_attachment_view.image = demo->buffers[i].image;
746 err = vkCreateImageView(demo->device, &color_attachment_view, NULL,
747 &demo->buffers[i].view);
751 demo->current_buffer = 0;
753 if (NULL != presentModes) {
758 static void demo_prepare_depth(struct demo *demo) {
759 const VkFormat depth_format = VK_FORMAT_D16_UNORM;
760 const VkImageCreateInfo image = {
761 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
763 .imageType = VK_IMAGE_TYPE_2D,
764 .format = depth_format,
765 .extent = {demo->width, demo->height, 1},
768 .samples = VK_SAMPLE_COUNT_1_BIT,
769 .tiling = VK_IMAGE_TILING_OPTIMAL,
770 .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
773 VkMemoryAllocateInfo mem_alloc = {
774 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
777 .memoryTypeIndex = 0,
779 VkImageViewCreateInfo view = {
780 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
782 .image = VK_NULL_HANDLE,
783 .format = depth_format,
784 .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
790 .viewType = VK_IMAGE_VIEW_TYPE_2D,
793 VkMemoryRequirements mem_reqs;
794 VkResult U_ASSERT_ONLY err;
795 bool U_ASSERT_ONLY pass;
797 demo->depth.format = depth_format;
800 err = vkCreateImage(demo->device, &image, NULL, &demo->depth.image);
803 /* get memory requirements for this object */
804 vkGetImageMemoryRequirements(demo->device, demo->depth.image, &mem_reqs);
806 /* select memory size and type */
807 mem_alloc.allocationSize = mem_reqs.size;
808 pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
809 0, /* No requirements */
810 &mem_alloc.memoryTypeIndex);
813 /* allocate memory */
814 err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &demo->depth.mem);
819 vkBindImageMemory(demo->device, demo->depth.image, demo->depth.mem, 0);
822 demo_set_image_layout(demo, demo->depth.image, VK_IMAGE_ASPECT_DEPTH_BIT,
823 VK_IMAGE_LAYOUT_UNDEFINED,
824 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
827 /* create image view */
828 view.image = demo->depth.image;
829 err = vkCreateImageView(demo->device, &view, NULL, &demo->depth.view);
834 demo_prepare_texture_image(struct demo *demo, const uint32_t *tex_colors,
835 struct texture_object *tex_obj, VkImageTiling tiling,
836 VkImageUsageFlags usage, VkFlags required_props) {
837 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
838 const int32_t tex_width = 2;
839 const int32_t tex_height = 2;
840 VkResult U_ASSERT_ONLY err;
841 bool U_ASSERT_ONLY pass;
843 tex_obj->tex_width = tex_width;
844 tex_obj->tex_height = tex_height;
846 const VkImageCreateInfo image_create_info = {
847 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
849 .imageType = VK_IMAGE_TYPE_2D,
850 .format = tex_format,
851 .extent = {tex_width, tex_height, 1},
854 .samples = VK_SAMPLE_COUNT_1_BIT,
858 .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED
860 VkMemoryAllocateInfo mem_alloc = {
861 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
864 .memoryTypeIndex = 0,
867 VkMemoryRequirements mem_reqs;
870 vkCreateImage(demo->device, &image_create_info, NULL, &tex_obj->image);
873 vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs);
875 mem_alloc.allocationSize = mem_reqs.size;
877 memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
878 required_props, &mem_alloc.memoryTypeIndex);
881 /* allocate memory */
882 err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &tex_obj->mem);
886 err = vkBindImageMemory(demo->device, tex_obj->image, tex_obj->mem, 0);
889 if (required_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
890 const VkImageSubresource subres = {
891 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
895 VkSubresourceLayout layout;
899 vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres,
902 err = vkMapMemory(demo->device, tex_obj->mem, 0,
903 mem_alloc.allocationSize, 0, &data);
906 for (y = 0; y < tex_height; y++) {
907 uint32_t *row = (uint32_t *)((char *)data + layout.rowPitch * y);
908 for (x = 0; x < tex_width; x++)
909 row[x] = tex_colors[(x & 1) ^ (y & 1)];
912 vkUnmapMemory(demo->device, tex_obj->mem);
915 tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
916 demo_set_image_layout(demo, tex_obj->image, VK_IMAGE_ASPECT_COLOR_BIT,
917 VK_IMAGE_LAYOUT_PREINITIALIZED, tex_obj->imageLayout,
918 VK_ACCESS_HOST_WRITE_BIT);
919 /* setting the image layout does not reference the actual memory so no need
920 * to add a mem ref */
923 static void demo_destroy_texture_image(struct demo *demo,
924 struct texture_object *tex_obj) {
925 /* clean up staging resources */
926 vkDestroyImage(demo->device, tex_obj->image, NULL);
927 vkFreeMemory(demo->device, tex_obj->mem, NULL);
930 static void demo_prepare_textures(struct demo *demo) {
931 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
932 VkFormatProperties props;
933 const uint32_t tex_colors[DEMO_TEXTURE_COUNT][2] = {
934 {0xffff0000, 0xff00ff00},
937 VkResult U_ASSERT_ONLY err;
939 vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props);
941 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
942 if ((props.linearTilingFeatures &
943 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
944 !demo->use_staging_buffer) {
945 /* Device can texture using linear textures */
946 demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i],
947 VK_IMAGE_TILING_LINEAR,
948 VK_IMAGE_USAGE_SAMPLED_BIT,
949 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
950 } else if (props.optimalTilingFeatures &
951 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
952 /* Must use staging buffer to copy linear texture to optimized */
953 struct texture_object staging_texture;
955 memset(&staging_texture, 0, sizeof(staging_texture));
956 demo_prepare_texture_image(demo, tex_colors[i], &staging_texture,
957 VK_IMAGE_TILING_LINEAR,
958 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
959 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
961 demo_prepare_texture_image(
962 demo, tex_colors[i], &demo->textures[i],
963 VK_IMAGE_TILING_OPTIMAL,
964 (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT),
965 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
967 demo_set_image_layout(demo, staging_texture.image,
968 VK_IMAGE_ASPECT_COLOR_BIT,
969 staging_texture.imageLayout,
970 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
973 demo_set_image_layout(demo, demo->textures[i].image,
974 VK_IMAGE_ASPECT_COLOR_BIT,
975 demo->textures[i].imageLayout,
976 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
979 VkImageCopy copy_region = {
980 .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
981 .srcOffset = {0, 0, 0},
982 .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
983 .dstOffset = {0, 0, 0},
984 .extent = {staging_texture.tex_width,
985 staging_texture.tex_height, 1},
988 demo->setup_cmd, staging_texture.image,
989 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, demo->textures[i].image,
990 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
992 demo_set_image_layout(demo, demo->textures[i].image,
993 VK_IMAGE_ASPECT_COLOR_BIT,
994 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
995 demo->textures[i].imageLayout,
998 demo_flush_init_cmd(demo);
1000 demo_destroy_texture_image(demo, &staging_texture);
1002 /* Can't support VK_FORMAT_B8G8R8A8_UNORM !? */
1003 assert(!"No support for B8G8R8A8_UNORM as texture image format");
1006 const VkSamplerCreateInfo sampler = {
1007 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
1009 .magFilter = VK_FILTER_NEAREST,
1010 .minFilter = VK_FILTER_NEAREST,
1011 .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
1012 .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
1013 .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
1014 .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
1016 .anisotropyEnable = VK_FALSE,
1018 .compareOp = VK_COMPARE_OP_NEVER,
1021 .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
1022 .unnormalizedCoordinates = VK_FALSE,
1024 VkImageViewCreateInfo view = {
1025 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1027 .image = VK_NULL_HANDLE,
1028 .viewType = VK_IMAGE_VIEW_TYPE_2D,
1029 .format = tex_format,
1032 VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
1033 VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A,
1035 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
1039 /* create sampler */
1040 err = vkCreateSampler(demo->device, &sampler, NULL,
1041 &demo->textures[i].sampler);
1044 /* create image view */
1045 view.image = demo->textures[i].image;
1046 err = vkCreateImageView(demo->device, &view, NULL,
1047 &demo->textures[i].view);
1052 static void demo_prepare_vertices(struct demo *demo) {
1054 const float vb[3][5] = {
1055 /* position texcoord */
1056 { -1.0f, -1.0f, 0.25f, 0.0f, 0.0f },
1057 { 1.0f, -1.0f, 0.25f, 1.0f, 0.0f },
1058 { 0.0f, 1.0f, 1.0f, 0.5f, 1.0f },
1061 const VkBufferCreateInfo buf_info = {
1062 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1065 .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
1068 VkMemoryAllocateInfo mem_alloc = {
1069 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1071 .allocationSize = 0,
1072 .memoryTypeIndex = 0,
1074 VkMemoryRequirements mem_reqs;
1075 VkResult U_ASSERT_ONLY err;
1076 bool U_ASSERT_ONLY pass;
1079 memset(&demo->vertices, 0, sizeof(demo->vertices));
1081 err = vkCreateBuffer(demo->device, &buf_info, NULL, &demo->vertices.buf);
1084 vkGetBufferMemoryRequirements(demo->device, demo->vertices.buf, &mem_reqs);
1087 mem_alloc.allocationSize = mem_reqs.size;
1088 pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
1089 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
1090 &mem_alloc.memoryTypeIndex);
1093 err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &demo->vertices.mem);
1096 err = vkMapMemory(demo->device, demo->vertices.mem, 0,
1097 mem_alloc.allocationSize, 0, &data);
1100 memcpy(data, vb, sizeof(vb));
1102 vkUnmapMemory(demo->device, demo->vertices.mem);
1104 err = vkBindBufferMemory(demo->device, demo->vertices.buf,
1105 demo->vertices.mem, 0);
1108 demo->vertices.vi.sType =
1109 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
1110 demo->vertices.vi.pNext = NULL;
1111 demo->vertices.vi.vertexBindingDescriptionCount = 1;
1112 demo->vertices.vi.pVertexBindingDescriptions = demo->vertices.vi_bindings;
1113 demo->vertices.vi.vertexAttributeDescriptionCount = 2;
1114 demo->vertices.vi.pVertexAttributeDescriptions = demo->vertices.vi_attrs;
1116 demo->vertices.vi_bindings[0].binding = VERTEX_BUFFER_BIND_ID;
1117 demo->vertices.vi_bindings[0].stride = sizeof(vb[0]);
1118 demo->vertices.vi_bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1120 demo->vertices.vi_attrs[0].binding = VERTEX_BUFFER_BIND_ID;
1121 demo->vertices.vi_attrs[0].location = 0;
1122 demo->vertices.vi_attrs[0].format = VK_FORMAT_R32G32B32_SFLOAT;
1123 demo->vertices.vi_attrs[0].offset = 0;
1125 demo->vertices.vi_attrs[1].binding = VERTEX_BUFFER_BIND_ID;
1126 demo->vertices.vi_attrs[1].location = 1;
1127 demo->vertices.vi_attrs[1].format = VK_FORMAT_R32G32_SFLOAT;
1128 demo->vertices.vi_attrs[1].offset = sizeof(float) * 3;
1131 static void demo_prepare_descriptor_layout(struct demo *demo) {
1132 const VkDescriptorSetLayoutBinding layout_binding = {
1134 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1135 .descriptorCount = DEMO_TEXTURE_COUNT,
1136 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
1137 .pImmutableSamplers = NULL,
1139 const VkDescriptorSetLayoutCreateInfo descriptor_layout = {
1140 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
1143 .pBindings = &layout_binding,
1145 VkResult U_ASSERT_ONLY err;
1147 err = vkCreateDescriptorSetLayout(demo->device, &descriptor_layout, NULL,
1148 &demo->desc_layout);
1151 const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {
1152 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1154 .setLayoutCount = 1,
1155 .pSetLayouts = &demo->desc_layout,
1158 err = vkCreatePipelineLayout(demo->device, &pPipelineLayoutCreateInfo, NULL,
1159 &demo->pipeline_layout);
1163 static void demo_prepare_render_pass(struct demo *demo) {
1164 const VkAttachmentDescription attachments[2] = {
1167 .format = demo->format,
1168 .samples = VK_SAMPLE_COUNT_1_BIT,
1169 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1170 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
1171 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1172 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1173 .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1174 .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1178 .format = demo->depth.format,
1179 .samples = VK_SAMPLE_COUNT_1_BIT,
1180 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1181 .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1182 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1183 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1185 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1187 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1190 const VkAttachmentReference color_reference = {
1191 .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1193 const VkAttachmentReference depth_reference = {
1195 .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1197 const VkSubpassDescription subpass = {
1198 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
1200 .inputAttachmentCount = 0,
1201 .pInputAttachments = NULL,
1202 .colorAttachmentCount = 1,
1203 .pColorAttachments = &color_reference,
1204 .pResolveAttachments = NULL,
1205 .pDepthStencilAttachment = &depth_reference,
1206 .preserveAttachmentCount = 0,
1207 .pPreserveAttachments = NULL,
1209 const VkRenderPassCreateInfo rp_info = {
1210 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
1212 .attachmentCount = 2,
1213 .pAttachments = attachments,
1215 .pSubpasses = &subpass,
1216 .dependencyCount = 0,
1217 .pDependencies = NULL,
1219 VkResult U_ASSERT_ONLY err;
1221 err = vkCreateRenderPass(demo->device, &rp_info, NULL, &demo->render_pass);
1225 static VkShaderModule
1226 demo_prepare_shader_module(struct demo *demo, const void *code, size_t size) {
1227 VkShaderModuleCreateInfo moduleCreateInfo;
1228 VkShaderModule module;
1229 VkResult U_ASSERT_ONLY err;
1231 moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1232 moduleCreateInfo.pNext = NULL;
1234 moduleCreateInfo.codeSize = size;
1235 moduleCreateInfo.pCode = code;
1236 moduleCreateInfo.flags = 0;
1237 err = vkCreateShaderModule(demo->device, &moduleCreateInfo, NULL, &module);
1243 char *demo_read_spv(const char *filename, size_t *psize) {
1248 FILE *fp = fopen(filename, "rb");
1252 fseek(fp, 0L, SEEK_END);
1255 fseek(fp, 0L, SEEK_SET);
1257 shader_code = malloc(size);
1258 retVal = fread(shader_code, size, 1, fp);
1271 static unsigned char vert_spirv_bin[] = {
1272 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00,
1273 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
1274 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,
1275 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1276 0x0F, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
1277 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1278 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00,
1279 0x04, 0x00, 0x09, 0x00, 0x47, 0x4C, 0x5F, 0x41, 0x52, 0x42, 0x5F, 0x73, 0x65, 0x70, 0x61, 0x72,
1280 0x61, 0x74, 0x65, 0x5F, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5F, 0x6F, 0x62, 0x6A, 0x65, 0x63,
1281 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4C, 0x5F, 0x41, 0x52, 0x42, 0x5F, 0x73,
1282 0x68, 0x61, 0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, 0x5F,
1283 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6B, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
1284 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00,
1285 0x74, 0x65, 0x78, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
1286 0x0B, 0x00, 0x00, 0x00, 0x61, 0x74, 0x74, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00,
1287 0x0E, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
1288 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1289 0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x05, 0x00, 0x03, 0x00,
1290 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00,
1291 0x70, 0x6F, 0x73, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
1292 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
1293 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1294 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00,
1295 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
1296 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
1297 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00,
1298 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
1299 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1300 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
1301 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1302 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
1303 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
1304 0x04, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
1305 0x20, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
1306 0x3B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1307 0x15, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1308 0x2B, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1309 0x20, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
1310 0x3B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1311 0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
1312 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1313 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
1314 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
1315 0x09, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00,
1316 0x15, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x16, 0x00, 0x00, 0x00,
1317 0x17, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
1318 0x17, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
1321 static VkShaderModule demo_prepare_vs(struct demo *demo) {
1322 void *vertShaderCode;
1325 /* insert shader binary for test convenience */
1326 /* vertShaderCode = demo_read_spv("tri-vert.spv", &size);*/
1327 vertShaderCode = vert_spirv_bin;
1328 size = sizeof(vert_spirv_bin)/sizeof(unsigned char);
1330 demo->vert_shader_module =
1331 demo_prepare_shader_module(demo, vertShaderCode, size);
1333 /*free(vertShaderCode);*/
1335 return demo->vert_shader_module;
1338 static unsigned char frag_spirv_bin[] = {
1339 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00,
1340 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
1341 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,
1342 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1343 0x0F, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
1344 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
1345 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
1346 0x90, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4C, 0x5F, 0x41, 0x52, 0x42, 0x5F, 0x73,
1347 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5F, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5F, 0x6F,
1348 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4C, 0x5F, 0x41,
1349 0x52, 0x42, 0x5F, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6E, 0x67, 0x5F, 0x6C, 0x61, 0x6E, 0x67, 0x75,
1350 0x61, 0x67, 0x65, 0x5F, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6B, 0x00, 0x05, 0x00, 0x04, 0x00,
1351 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
1352 0x09, 0x00, 0x00, 0x00, 0x75, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00,
1353 0x05, 0x00, 0x03, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x00, 0x05, 0x00, 0x05, 0x00,
1354 0x11, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00,
1355 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1356 0x47, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1357 0x47, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1358 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1359 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
1360 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
1361 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
1362 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
1363 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1364 0x19, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1366 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
1367 0x20, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
1368 0x3B, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1369 0x17, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1370 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
1371 0x3B, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1372 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1373 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
1374 0x0B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
1375 0x0F, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00,
1376 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
1377 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00,
1378 0x38, 0x00, 0x01, 0x00,
1381 static VkShaderModule demo_prepare_fs(struct demo *demo) {
1382 void *fragShaderCode;
1385 /* insert shader binary for test convenience */
1386 /*fragShaderCode = demo_read_spv("tri-frag.spv", &size);*/
1387 fragShaderCode = frag_spirv_bin;
1388 size = sizeof(frag_spirv_bin)/sizeof(unsigned char);
1390 demo->frag_shader_module =
1391 demo_prepare_shader_module(demo, fragShaderCode, size);
1393 /*free(fragShaderCode);*/
1395 return demo->frag_shader_module;
1398 static void demo_prepare_pipeline(struct demo *demo) {
1399 VkGraphicsPipelineCreateInfo pipeline;
1400 VkPipelineCacheCreateInfo pipelineCache;
1402 VkPipelineVertexInputStateCreateInfo vi;
1403 VkPipelineInputAssemblyStateCreateInfo ia;
1404 VkPipelineRasterizationStateCreateInfo rs;
1405 VkPipelineColorBlendStateCreateInfo cb;
1406 VkPipelineDepthStencilStateCreateInfo ds;
1407 VkPipelineViewportStateCreateInfo vp;
1408 VkPipelineMultisampleStateCreateInfo ms;
1409 VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE];
1410 VkPipelineDynamicStateCreateInfo dynamicState;
1412 VkResult U_ASSERT_ONLY err;
1414 memset(dynamicStateEnables, 0, sizeof dynamicStateEnables);
1415 memset(&dynamicState, 0, sizeof dynamicState);
1416 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
1417 dynamicState.pDynamicStates = dynamicStateEnables;
1419 memset(&pipeline, 0, sizeof(pipeline));
1420 pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
1421 pipeline.layout = demo->pipeline_layout;
1423 vi = demo->vertices.vi;
1425 memset(&ia, 0, sizeof(ia));
1426 ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
1427 ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1429 memset(&rs, 0, sizeof(rs));
1430 rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
1431 rs.polygonMode = VK_POLYGON_MODE_FILL;
1432 rs.cullMode = VK_CULL_MODE_BACK_BIT;
1433 rs.frontFace = VK_FRONT_FACE_CLOCKWISE;
1434 rs.depthClampEnable = VK_FALSE;
1435 rs.rasterizerDiscardEnable = VK_FALSE;
1436 rs.depthBiasEnable = VK_FALSE;
1438 memset(&cb, 0, sizeof(cb));
1439 cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
1440 VkPipelineColorBlendAttachmentState att_state[1];
1441 memset(att_state, 0, sizeof(att_state));
1442 att_state[0].colorWriteMask = 0xf;
1443 att_state[0].blendEnable = VK_FALSE;
1444 cb.attachmentCount = 1;
1445 cb.pAttachments = att_state;
1447 memset(&vp, 0, sizeof(vp));
1448 vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
1449 vp.viewportCount = 1;
1450 dynamicStateEnables[dynamicState.dynamicStateCount++] =
1451 VK_DYNAMIC_STATE_VIEWPORT;
1452 vp.scissorCount = 1;
1453 dynamicStateEnables[dynamicState.dynamicStateCount++] =
1454 VK_DYNAMIC_STATE_SCISSOR;
1456 memset(&ds, 0, sizeof(ds));
1457 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
1458 ds.depthTestEnable = VK_TRUE;
1459 ds.depthWriteEnable = VK_TRUE;
1460 ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
1461 ds.depthBoundsTestEnable = VK_FALSE;
1462 ds.back.failOp = VK_STENCIL_OP_KEEP;
1463 ds.back.passOp = VK_STENCIL_OP_KEEP;
1464 ds.back.compareOp = VK_COMPARE_OP_ALWAYS;
1465 ds.stencilTestEnable = VK_FALSE;
1468 memset(&ms, 0, sizeof(ms));
1469 ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
1470 ms.pSampleMask = NULL;
1471 ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
1473 // Two stages: vs and fs
1474 pipeline.stageCount = 2;
1475 VkPipelineShaderStageCreateInfo shaderStages[2];
1476 memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo));
1478 shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1479 shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
1480 shaderStages[0].module = demo_prepare_vs(demo);
1481 shaderStages[0].pName = "main";
1483 shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1484 shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1485 shaderStages[1].module = demo_prepare_fs(demo);
1486 shaderStages[1].pName = "main";
1488 pipeline.pVertexInputState = &vi;
1489 pipeline.pInputAssemblyState = &ia;
1490 pipeline.pRasterizationState = &rs;
1491 pipeline.pColorBlendState = &cb;
1492 pipeline.pMultisampleState = &ms;
1493 pipeline.pViewportState = &vp;
1494 pipeline.pDepthStencilState = &ds;
1495 pipeline.pStages = shaderStages;
1496 pipeline.renderPass = demo->render_pass;
1497 pipeline.pDynamicState = &dynamicState;
1499 memset(&pipelineCache, 0, sizeof(pipelineCache));
1500 pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
1502 err = vkCreatePipelineCache(demo->device, &pipelineCache, NULL,
1503 &demo->pipelineCache);
1505 err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1,
1506 &pipeline, NULL, &demo->pipeline);
1509 vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL);
1511 vkDestroyShaderModule(demo->device, demo->frag_shader_module, NULL);
1512 vkDestroyShaderModule(demo->device, demo->vert_shader_module, NULL);
1515 static void demo_prepare_descriptor_pool(struct demo *demo) {
1516 const VkDescriptorPoolSize type_count = {
1517 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1518 .descriptorCount = DEMO_TEXTURE_COUNT,
1520 const VkDescriptorPoolCreateInfo descriptor_pool = {
1521 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1525 .pPoolSizes = &type_count,
1527 VkResult U_ASSERT_ONLY err;
1529 err = vkCreateDescriptorPool(demo->device, &descriptor_pool, NULL,
1534 static void demo_prepare_descriptor_set(struct demo *demo) {
1535 VkDescriptorImageInfo tex_descs[DEMO_TEXTURE_COUNT];
1536 VkWriteDescriptorSet write;
1537 VkResult U_ASSERT_ONLY err;
1540 VkDescriptorSetAllocateInfo alloc_info = {
1541 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1543 .descriptorPool = demo->desc_pool,
1544 .descriptorSetCount = 1,
1545 .pSetLayouts = &demo->desc_layout};
1546 err = vkAllocateDescriptorSets(demo->device, &alloc_info, &demo->desc_set);
1549 memset(&tex_descs, 0, sizeof(tex_descs));
1550 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1551 tex_descs[i].sampler = demo->textures[i].sampler;
1552 tex_descs[i].imageView = demo->textures[i].view;
1553 tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
1556 memset(&write, 0, sizeof(write));
1557 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1558 write.dstSet = demo->desc_set;
1559 write.descriptorCount = DEMO_TEXTURE_COUNT;
1560 write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1561 write.pImageInfo = tex_descs;
1563 vkUpdateDescriptorSets(demo->device, 1, &write, 0, NULL);
1566 static void demo_prepare_framebuffers(struct demo *demo) {
1567 VkImageView attachments[2];
1568 attachments[1] = demo->depth.view;
1570 const VkFramebufferCreateInfo fb_info = {
1571 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1573 .renderPass = demo->render_pass,
1574 .attachmentCount = 2,
1575 .pAttachments = attachments,
1576 .width = demo->width,
1577 .height = demo->height,
1580 VkResult U_ASSERT_ONLY err;
1583 demo->framebuffers = (VkFramebuffer *)malloc(demo->swapchainImageCount *
1584 sizeof(VkFramebuffer));
1585 assert(demo->framebuffers);
1587 for (i = 0; i < demo->swapchainImageCount; i++) {
1588 attachments[0] = demo->buffers[i].view;
1589 err = vkCreateFramebuffer(demo->device, &fb_info, NULL,
1590 &demo->framebuffers[i]);
1595 static void demo_prepare(struct demo *demo) {
1596 VkResult U_ASSERT_ONLY err;
1598 const VkCommandPoolCreateInfo cmd_pool_info = {
1599 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1601 .queueFamilyIndex = demo->graphics_queue_node_index,
1602 .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
1604 err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL,
1608 const VkCommandBufferAllocateInfo cmd = {
1609 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1611 .commandPool = demo->cmd_pool,
1612 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1613 .commandBufferCount = 1,
1615 err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->draw_cmd);
1618 demo_prepare_buffers(demo);
1619 demo_prepare_depth(demo);
1620 demo_prepare_textures(demo);
1621 demo_prepare_vertices(demo);
1622 demo_prepare_descriptor_layout(demo);
1623 demo_prepare_render_pass(demo);
1624 demo_prepare_pipeline(demo);
1626 demo_prepare_descriptor_pool(demo);
1627 demo_prepare_descriptor_set(demo);
1629 demo_prepare_framebuffers(demo);
1631 demo->prepared = true;
1635 static void demo_run(struct demo *demo) {
1636 if (!demo->prepared)
1640 if (demo->depthStencil > 0.99f)
1641 demo->depthIncrement = -0.001f;
1642 if (demo->depthStencil < 0.8f)
1643 demo->depthIncrement = 0.001f;
1645 demo->depthStencil += demo->depthIncrement;
1648 if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) {
1649 PostQuitMessage(validation_error);
1653 // On MS-Windows, make this a global, so it's available to WndProc()
1656 // MS-Windows event handling function:
1657 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
1658 char tmp_str[] = APP_LONG_NAME;
1664 PostQuitMessage(validation_error);
1667 if (demo.prepared) {
1672 // Resize the application to the new window size, except when
1673 // it was minimized. Vulkan doesn't support images or swapchains
1674 // with width=0 and height=0.
1675 if (wParam != SIZE_MINIMIZED) {
1676 demo.width = lParam & 0xffff;
1677 demo.height = lParam & 0xffff0000 >> 16;
1684 return (DefWindowProc(hWnd, uMsg, wParam, lParam));
1687 static void demo_create_window(struct demo *demo) {
1688 WNDCLASSEX win_class;
1690 // Initialize the window class structure:
1691 win_class.cbSize = sizeof(WNDCLASSEX);
1692 win_class.style = CS_HREDRAW | CS_VREDRAW;
1693 win_class.lpfnWndProc = WndProc;
1694 win_class.cbClsExtra = 0;
1695 win_class.cbWndExtra = 0;
1696 win_class.hInstance = demo->connection; // hInstance
1697 win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1698 win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
1699 win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
1700 win_class.lpszMenuName = NULL;
1701 win_class.lpszClassName = demo->name;
1702 win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
1703 // Register window class:
1704 if (!RegisterClassEx(&win_class)) {
1705 // It didn't work, so try to give a useful error:
1706 printf("Unexpected error trying to start the application!\n");
1710 // Create window with the registered class:
1711 RECT wr = {0, 0, demo->width, demo->height};
1712 AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
1713 demo->window = CreateWindowEx(0,
1714 demo->name, // class name
1715 demo->name, // app name
1716 WS_OVERLAPPEDWINDOW | // window style
1717 WS_VISIBLE | WS_SYSMENU,
1718 100, 100, // x/y coords
1719 wr.right - wr.left, // width
1720 wr.bottom - wr.top, // height
1721 NULL, // handle to parent
1722 NULL, // handle to menu
1723 demo->connection, // hInstance
1724 NULL); // no extra parameters
1725 if (!demo->window) {
1726 // It didn't work, so try to give a useful error:
1727 printf("Cannot create a window in which to draw!\n");
1734 static void demo_run(struct demo *demo) {
1736 while (!demo->quit) {
1739 if (demo->depthStencil > 0.99f)
1740 demo->depthIncrement = -0.001f;
1741 if (demo->depthStencil < 0.8f)
1742 demo->depthIncrement = 0.001f;
1744 demo->depthStencil += demo->depthIncrement;
1746 // Wait for work to finish before updating MVP.
1747 vkDeviceWaitIdle(demo->device);
1749 if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
1755 handle_ping(void *data, struct wl_shell_surface *shell_surface,
1757 printf("%s\n", __func__);
1758 wl_shell_surface_pong(shell_surface, serial);
1762 handle_configure(void *data, struct wl_shell_surface *shell_surface,
1763 uint32_t edges, int32_t width, int32_t height) {
1764 printf("%s, (%d, %d)\n", __func__, width, height);
1768 handle_popup_done(void *data, struct wl_shell_surface *shell_surface) {
1771 static const struct wl_shell_surface_listener shell_surface_listener = {
1777 static void demo_create_window(struct demo *demo) {
1778 demo->wl_surface = wl_compositor_create_surface(demo->compositor);
1780 demo->shell_surface = wl_shell_get_shell_surface(demo->shell, demo->wl_surface);
1782 if (demo->shell_surface) {
1783 wl_shell_surface_add_listener(demo->shell_surface,
1784 &shell_surface_listener, demo);
1785 wl_shell_surface_set_toplevel(demo->shell_surface);
1788 wl_surface_set_user_data(demo->wl_surface, demo);
1789 wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME);
1794 * Return 1 (true) if all layer names specified in check_names
1795 * can be found in given layer properties.
1797 static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
1798 uint32_t layer_count,
1799 VkLayerProperties *layers) {
1801 for (i = 0; i < check_count; i++) {
1803 for (j = 0; j < layer_count; j++) {
1804 if (!strcmp(check_names[i], layers[j].layerName)) {
1810 fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
1817 static void demo_init_vk(struct demo *demo) {
1819 uint32_t instance_extension_count = 0;
1820 uint32_t instance_layer_count = 0;
1821 uint32_t device_validation_layer_count = 0;
1822 char **instance_validation_layers = NULL;
1824 demo->enabled_extension_count = 0;
1825 demo->enabled_layer_count = 0;
1827 char *instance_validation_layers_alt1[] = {
1828 "VK_LAYER_LUNARG_standard_validation"
1831 char *instance_validation_layers_alt2[] = {
1832 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation",
1833 "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker",
1834 "VK_LAYER_LUNARG_image", "VK_LAYER_LUNARG_core_validation",
1835 "VK_LAYER_LUNARG_swapchain", "VK_LAYER_GOOGLE_unique_objects"
1838 /* Look for validation layers */
1839 VkBool32 validation_found = 0;
1840 if (demo->validate) {
1842 err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
1845 instance_validation_layers = instance_validation_layers_alt1;
1846 if (instance_layer_count > 0) {
1847 VkLayerProperties *instance_layers =
1848 malloc(sizeof (VkLayerProperties) * instance_layer_count);
1849 err = vkEnumerateInstanceLayerProperties(&instance_layer_count,
1854 validation_found = demo_check_layers(
1855 ARRAY_SIZE(instance_validation_layers_alt1),
1856 instance_validation_layers, instance_layer_count,
1858 if (validation_found) {
1859 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
1860 demo->device_validation_layers[0] = "VK_LAYER_LUNARG_standard_validation";
1861 device_validation_layer_count = 1;
1863 // use alternative set of validation layers
1864 instance_validation_layers = instance_validation_layers_alt2;
1865 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
1866 validation_found = demo_check_layers(
1867 ARRAY_SIZE(instance_validation_layers_alt2),
1868 instance_validation_layers, instance_layer_count,
1870 device_validation_layer_count =
1871 ARRAY_SIZE(instance_validation_layers_alt2);
1872 for (i = 0; i < device_validation_layer_count; i++) {
1873 demo->device_validation_layers[i] =
1874 instance_validation_layers[i];
1877 free(instance_layers);
1880 if (!validation_found) {
1881 ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find"
1882 "required validation layer.\n\n"
1883 "Please look at the Getting Started guide for additional "
1885 "vkCreateInstance Failure");
1889 /* Look for instance extensions */
1890 VkBool32 surfaceExtFound = 0;
1891 VkBool32 platformSurfaceExtFound = 0;
1892 memset(demo->extension_names, 0, sizeof(demo->extension_names));
1894 err = vkEnumerateInstanceExtensionProperties(
1895 NULL, &instance_extension_count, NULL);
1898 if (instance_extension_count > 0) {
1900 VkExtensionProperties *instance_extensions =
1901 malloc(sizeof(VkExtensionProperties) * instance_extension_count);
1902 err = vkEnumerateInstanceExtensionProperties(
1903 NULL, &instance_extension_count, instance_extensions);
1905 for (i = 0; i < instance_extension_count; i++) {
1906 if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME,
1907 instance_extensions[i].extensionName)) {
1908 surfaceExtFound = 1;
1909 demo->extension_names[demo->enabled_extension_count++] =
1910 VK_KHR_SURFACE_EXTENSION_NAME;
1913 if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
1914 instance_extensions[i].extensionName)) {
1915 platformSurfaceExtFound = 1;
1916 demo->extension_names[demo->enabled_extension_count++] =
1917 VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
1920 if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
1921 instance_extensions[i].extensionName)) {
1922 platformSurfaceExtFound = 1;
1923 demo->extension_names[demo->enabled_extension_count++] =
1924 VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
1927 if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
1928 instance_extensions[i].extensionName)) {
1929 if (demo->validate) {
1930 demo->extension_names[demo->enabled_extension_count++] =
1931 VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
1934 assert(demo->enabled_extension_count < 64);
1937 free(instance_extensions);
1940 if (!surfaceExtFound) {
1941 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1942 "the " VK_KHR_SURFACE_EXTENSION_NAME
1943 " extension.\n\nDo you have a compatible "
1944 "Vulkan installable client driver (ICD) installed?\nPlease "
1945 "look at the Getting Started guide for additional "
1947 "vkCreateInstance Failure");
1949 if (!platformSurfaceExtFound) {
1951 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1952 "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME
1953 " extension.\n\nDo you have a compatible "
1954 "Vulkan installable client driver (ICD) installed?\nPlease "
1955 "look at the Getting Started guide for additional "
1957 "vkCreateInstance Failure");
1959 ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1960 "the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
1961 " extension.\n\nDo you have a compatible "
1962 "Vulkan installable client driver (ICD) installed?\nPlease "
1963 "look at the Getting Started guide for additional "
1965 "vkCreateInstance Failure");
1968 const VkApplicationInfo app = {
1969 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
1971 .pApplicationName = APP_SHORT_NAME,
1972 .applicationVersion = 0,
1973 .pEngineName = APP_SHORT_NAME,
1975 .apiVersion = VK_API_VERSION_1_0,
1977 VkInstanceCreateInfo inst_info = {
1978 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
1980 .pApplicationInfo = &app,
1981 .enabledLayerCount = demo->enabled_layer_count,
1982 .ppEnabledLayerNames = (const char *const *)instance_validation_layers,
1983 .enabledExtensionCount = demo->enabled_extension_count,
1984 .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
1989 err = vkCreateInstance(&inst_info, NULL, &demo->inst);
1990 if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
1991 ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
1992 "(ICD).\n\nPlease look at the Getting Started guide for "
1993 "additional information.\n",
1994 "vkCreateInstance Failure");
1995 } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
1996 ERR_EXIT("Cannot find a specified extension library"
1997 ".\nMake sure your layers path is set appropriately\n",
1998 "vkCreateInstance Failure");
2000 ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
2001 "installable client driver (ICD) installed?\nPlease look at "
2002 "the Getting Started guide for additional information.\n",
2003 "vkCreateInstance Failure");
2006 /* Make initial call to query gpu_count, then second call for gpu info*/
2007 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
2008 assert(!err && gpu_count > 0);
2010 if (gpu_count > 0) {
2011 VkPhysicalDevice *physical_devices =
2012 malloc(sizeof(VkPhysicalDevice) * gpu_count);
2013 err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count,
2016 /* For tri demo we just grab the first physical device */
2017 demo->gpu = physical_devices[0];
2018 free(physical_devices);
2020 ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible devices."
2021 "\n\nDo you have a compatible Vulkan installable client"
2022 " driver (ICD) installed?\nPlease look at the Getting Started"
2023 " guide for additional information.\n",
2024 "vkEnumeratePhysicalDevices Failure");
2027 /* Look for validation layers */
2028 if (demo->validate) {
2029 validation_found = 0;
2030 demo->enabled_layer_count = 0;
2031 uint32_t device_layer_count = 0;
2033 vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, NULL);
2036 if (device_layer_count > 0) {
2037 VkLayerProperties *device_layers =
2038 malloc(sizeof (VkLayerProperties) * device_layer_count);
2039 err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count,
2044 validation_found = demo_check_layers(device_validation_layer_count,
2045 demo->device_validation_layers,
2048 demo->enabled_layer_count = device_validation_layer_count;
2050 free(device_layers);
2053 if (!validation_found) {
2054 ERR_EXIT("vkEnumerateDeviceLayerProperties failed to find "
2055 "a required validation layer.\n\n"
2056 "Please look at the Getting Started guide for additional "
2058 "vkCreateDevice Failure");
2062 /* Look for device extensions */
2063 uint32_t device_extension_count = 0;
2064 VkBool32 swapchainExtFound = 0;
2065 demo->enabled_extension_count = 0;
2066 memset(demo->extension_names, 0, sizeof(demo->extension_names));
2068 err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL,
2069 &device_extension_count, NULL);
2072 if (device_extension_count > 0) {
2074 VkExtensionProperties *device_extensions =
2075 malloc(sizeof(VkExtensionProperties) * device_extension_count);
2076 err = vkEnumerateDeviceExtensionProperties(
2077 demo->gpu, NULL, &device_extension_count, device_extensions);
2080 for (i = 0; i < device_extension_count; i++) {
2081 if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,
2082 device_extensions[i].extensionName)) {
2083 swapchainExtFound = 1;
2084 demo->extension_names[demo->enabled_extension_count++] =
2085 VK_KHR_SWAPCHAIN_EXTENSION_NAME;
2087 assert(demo->enabled_extension_count < 64);
2090 free(device_extensions);
2093 if (!swapchainExtFound) {
2094 ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find "
2095 "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME
2096 " extension.\n\nDo you have a compatible "
2097 "Vulkan installable client driver (ICD) installed?\nPlease "
2098 "look at the Getting Started guide for additional "
2100 "vkCreateInstance Failure");
2103 if (demo->validate) {
2104 demo->CreateDebugReportCallback =
2105 (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(
2106 demo->inst, "vkCreateDebugReportCallbackEXT");
2107 demo->DestroyDebugReportCallback =
2108 (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(
2109 demo->inst, "vkDestroyDebugReportCallbackEXT");
2110 if (!demo->CreateDebugReportCallback) {
2112 "GetProcAddr: Unable to find vkCreateDebugReportCallbackEXT\n",
2113 "vkGetProcAddr Failure");
2115 if (!demo->DestroyDebugReportCallback) {
2117 "GetProcAddr: Unable to find vkDestroyDebugReportCallbackEXT\n",
2118 "vkGetProcAddr Failure");
2120 demo->DebugReportMessage =
2121 (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(
2122 demo->inst, "vkDebugReportMessageEXT");
2123 if (!demo->DebugReportMessage) {
2124 ERR_EXIT("GetProcAddr: Unable to find vkDebugReportMessageEXT\n",
2125 "vkGetProcAddr Failure");
2128 VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
2129 dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
2130 dbgCreateInfo.flags =
2131 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
2132 dbgCreateInfo.pfnCallback = demo->use_break ? BreakCallback : dbgFunc;
2133 dbgCreateInfo.pUserData = NULL;
2134 dbgCreateInfo.pNext = NULL;
2135 err = demo->CreateDebugReportCallback(demo->inst, &dbgCreateInfo, NULL,
2136 &demo->msg_callback);
2140 case VK_ERROR_OUT_OF_HOST_MEMORY:
2141 ERR_EXIT("CreateDebugReportCallback: out of host memory\n",
2142 "CreateDebugReportCallback Failure");
2145 ERR_EXIT("CreateDebugReportCallback: unknown failure\n",
2146 "CreateDebugReportCallback Failure");
2151 // Having these GIPA queries of device extension entry points both
2152 // BEFORE and AFTER vkCreateDevice is a good test for the loader
2153 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceCapabilitiesKHR);
2154 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR);
2155 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR);
2156 GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR);
2157 GET_INSTANCE_PROC_ADDR(demo->inst, CreateSwapchainKHR);
2158 GET_INSTANCE_PROC_ADDR(demo->inst, DestroySwapchainKHR);
2159 GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR);
2160 GET_INSTANCE_PROC_ADDR(demo->inst, AcquireNextImageKHR);
2161 GET_INSTANCE_PROC_ADDR(demo->inst, QueuePresentKHR);
2163 vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
2165 // Query with NULL data to get count
2166 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
2169 demo->queue_props = (VkQueueFamilyProperties *)malloc(
2170 demo->queue_count * sizeof(VkQueueFamilyProperties));
2171 vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
2173 assert(demo->queue_count >= 1);
2175 VkPhysicalDeviceFeatures features;
2176 vkGetPhysicalDeviceFeatures(demo->gpu, &features);
2178 #if 0 /* Temporarily disable checking shader clip distance feature. */
2179 if (!features.shaderClipDistance) {
2180 ERR_EXIT("Required device feature `shaderClipDistance` not supported\n",
2181 "GetPhysicalDeviceFeatures failure");
2185 // Graphics queue and MemMgr queue can be separate.
2186 // TODO: Add support for separate queues, including synchronization,
2187 // and appropriate tracking for QueueSubmit
2190 static void demo_init_device(struct demo *demo) {
2191 VkResult U_ASSERT_ONLY err;
2193 float queue_priorities[1] = {0.0};
2194 const VkDeviceQueueCreateInfo queue = {
2195 .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
2197 .queueFamilyIndex = demo->graphics_queue_node_index,
2199 .pQueuePriorities = queue_priorities};
2201 VkPhysicalDeviceFeatures features = {
2202 .shaderClipDistance = VK_TRUE,
2205 VkDeviceCreateInfo device = {
2206 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
2208 .queueCreateInfoCount = 1,
2209 .pQueueCreateInfos = &queue,
2210 .enabledLayerCount = demo->enabled_layer_count,
2211 .ppEnabledLayerNames =
2212 (const char *const *)((demo->validate)
2213 ? demo->device_validation_layers
2215 .enabledExtensionCount = demo->enabled_extension_count,
2216 .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
2217 .pEnabledFeatures = &features,
2220 err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
2224 static void demo_init_vk_swapchain(struct demo *demo) {
2225 VkResult U_ASSERT_ONLY err;
2228 // Create a WSI surface for the window:
2230 VkWin32SurfaceCreateInfoKHR createInfo;
2231 createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
2232 createInfo.pNext = NULL;
2233 createInfo.flags = 0;
2234 createInfo.hinstance = demo->connection;
2235 createInfo.hwnd = demo->window;
2238 vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
2241 VkWaylandSurfaceCreateInfoKHR createInfo;
2242 createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
2243 createInfo.pNext = NULL;
2244 createInfo.flags = 0;
2245 createInfo.display = demo->display;
2246 createInfo.surface = demo->wl_surface;
2248 err = vkCreateWaylandSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
2251 // Iterate over each queue to learn whether it supports presenting:
2252 VkBool32 *supportsPresent =
2253 (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32));
2254 for (i = 0; i < demo->queue_count; i++) {
2255 demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface,
2256 &supportsPresent[i]);
2259 // Search for a graphics and a present queue in the array of queue
2260 // families, try to find one that supports both
2261 uint32_t graphicsQueueNodeIndex = UINT32_MAX;
2262 uint32_t presentQueueNodeIndex = UINT32_MAX;
2263 for (i = 0; i < demo->queue_count; i++) {
2264 if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
2265 if (graphicsQueueNodeIndex == UINT32_MAX) {
2266 graphicsQueueNodeIndex = i;
2269 if (supportsPresent[i] == VK_TRUE) {
2270 graphicsQueueNodeIndex = i;
2271 presentQueueNodeIndex = i;
2276 if (presentQueueNodeIndex == UINT32_MAX) {
2277 // If didn't find a queue that supports both graphics and present, then
2278 // find a separate present queue.
2280 for (i = 0; i < demo->queue_count; ++i) {
2281 if (supportsPresent[i] == VK_TRUE) {
2282 presentQueueNodeIndex = i;
2287 free(supportsPresent);
2289 // Generate error if could not find both a graphics and a present queue
2290 if (graphicsQueueNodeIndex == UINT32_MAX ||
2291 presentQueueNodeIndex == UINT32_MAX) {
2292 ERR_EXIT("Could not find a graphics and a present queue\n",
2293 "Swapchain Initialization Failure");
2296 // TODO: Add support for separate queues, including presentation,
2297 // synchronization, and appropriate tracking for QueueSubmit.
2298 // NOTE: While it is possible for an application to use a separate graphics
2299 // and a present queues, this demo program assumes it is only using
2301 if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
2302 ERR_EXIT("Could not find a common graphics and a present queue\n",
2303 "Swapchain Initialization Failure");
2306 demo->graphics_queue_node_index = graphicsQueueNodeIndex;
2308 demo_init_device(demo);
2310 vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 0,
2313 // Get the list of VkFormat's that are supported:
2314 uint32_t formatCount;
2315 err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
2316 &formatCount, NULL);
2318 VkSurfaceFormatKHR *surfFormats =
2319 (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
2320 err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
2321 &formatCount, surfFormats);
2323 // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
2324 // the surface has no preferred format. Otherwise, at least one
2325 // supported format will be returned.
2326 if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
2327 demo->format = VK_FORMAT_B8G8R8A8_UNORM;
2329 assert(formatCount >= 1);
2330 demo->format = surfFormats[0].format;
2332 demo->color_space = surfFormats[0].colorSpace;
2337 // Get Memory information and properties
2338 vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
2342 registry_handle_global(void *data, struct wl_registry *registry,
2343 uint32_t name, const char *interface, uint32_t version) {
2344 struct demo *d = data;
2346 printf("%s, interface: %s\n", __func__, interface);
2348 if (strcmp(interface, "wl_compositor") == 0) {
2350 wl_registry_bind(registry, name,
2351 &wl_compositor_interface, 1);
2352 } else if (strcmp(interface, "wl_shm") == 0) {
2353 d->shm = wl_registry_bind(registry, name,
2354 &wl_shm_interface, 1);
2355 } else if (strcmp(interface, "wl_shell") == 0) {
2357 wl_registry_bind(registry, name,
2358 &wl_shell_interface, 1);
2363 registry_handle_global_remove(void *data, struct wl_registry *registry,
2367 static const struct wl_registry_listener registry_listener = {
2368 registry_handle_global,
2369 registry_handle_global_remove
2372 static void demo_init_connection(struct demo *demo) {
2374 demo->display = wl_display_connect(NULL);
2376 if (demo->display == NULL) {
2377 printf("Cannot find a compatible Vulkan installable client driver "
2378 "(ICD).\nExiting ...\n");
2383 demo->registry = wl_display_get_registry(demo->display);
2384 wl_registry_add_listener(demo->registry, ®istry_listener, demo);
2385 wl_display_dispatch(demo->display);
2389 static void demo_init(struct demo *demo, const int argc, const char *argv[])
2393 memset(demo, 0, sizeof(*demo));
2394 demo->frameCount = INT32_MAX;
2396 for (i = 1; i < argc; i++) {
2397 if (strcmp(argv[i], "--use_staging") == 0) {
2398 demo->use_staging_buffer = true;
2401 if (strcmp(argv[i], "--break") == 0) {
2402 demo->use_break = true;
2405 if (strcmp(argv[i], "--validate") == 0) {
2406 demo->validate = true;
2409 if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX &&
2410 i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 &&
2411 demo->frameCount >= 0) {
2416 fprintf(stderr, "Usage:\n %s [--use_staging] [--validate] [--break] "
2417 "[--c <framecount>]\n",
2423 demo_init_connection(demo);
2427 demo->height = 2560;
2428 demo->depthStencil = 1.0;
2429 demo->depthIncrement = -0.01f;
2432 static void demo_cleanup(struct demo *demo) {
2435 demo->prepared = false;
2437 for (i = 0; i < demo->swapchainImageCount; i++) {
2438 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2440 free(demo->framebuffers);
2441 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2443 if (demo->setup_cmd) {
2444 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2446 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2447 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2449 vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2450 vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2451 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2452 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2454 vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2455 vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2457 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2458 vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2459 vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2460 vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2461 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2464 for (i = 0; i < demo->swapchainImageCount; i++) {
2465 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2468 vkDestroyImageView(demo->device, demo->depth.view, NULL);
2469 vkDestroyImage(demo->device, demo->depth.image, NULL);
2470 vkFreeMemory(demo->device, demo->depth.mem, NULL);
2472 demo->fpDestroySwapchainKHR(demo->device, demo->swapchain, NULL);
2473 free(demo->buffers);
2475 vkDestroyDevice(demo->device, NULL);
2476 if (demo->validate) {
2477 demo->DestroyDebugReportCallback(demo->inst, demo->msg_callback, NULL);
2479 vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
2480 vkDestroyInstance(demo->inst, NULL);
2482 free(demo->queue_props);
2485 static void demo_resize(struct demo *demo) {
2488 // Don't react to resize until after first initialization.
2489 if (!demo->prepared) {
2492 // In order to properly resize the window, we must re-create the swapchain
2493 // AND redo the command buffers, etc.
2495 // First, perform part of the demo_cleanup() function:
2496 demo->prepared = false;
2498 for (i = 0; i < demo->swapchainImageCount; i++) {
2499 vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2501 free(demo->framebuffers);
2502 vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2504 if (demo->setup_cmd) {
2505 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2507 vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2508 vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2510 vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2511 vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2512 vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2513 vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2515 vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2516 vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2518 for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2519 vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2520 vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2521 vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2522 vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2525 for (i = 0; i < demo->swapchainImageCount; i++) {
2526 vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2529 vkDestroyImageView(demo->device, demo->depth.view, NULL);
2530 vkDestroyImage(demo->device, demo->depth.image, NULL);
2531 vkFreeMemory(demo->device, demo->depth.mem, NULL);
2533 free(demo->buffers);
2535 // Second, re-perform the demo_prepare() function, which will re-create the
2541 // Include header required for parsing the command line options.
2542 #include <shellapi.h>
2544 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
2545 LPSTR pCmdLine, int nCmdShow) {
2547 bool done; // flag saying when app is complete
2551 // Use the CommandLine functions to get the command line arguments.
2552 // Unfortunately, Microsoft outputs
2553 // this information as wide characters for Unicode, and we simply want the
2554 // Ascii version to be compatible
2555 // with the non-Windows side. So, we have to convert the information to
2556 // Ascii character strings.
2557 LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc);
2558 if (NULL == commandLineArgs) {
2563 argv = (char **)malloc(sizeof(char *) * argc);
2567 for (int iii = 0; iii < argc; iii++) {
2568 size_t wideCharLen = wcslen(commandLineArgs[iii]);
2569 size_t numConverted = 0;
2571 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1));
2572 if (argv[iii] != NULL) {
2573 wcstombs_s(&numConverted, argv[iii], wideCharLen + 1,
2574 commandLineArgs[iii], wideCharLen + 1);
2582 demo_init(&demo, argc, argv);
2584 // Free up the items we had to allocate for the command line arguments.
2585 if (argc > 0 && argv != NULL) {
2586 for (int iii = 0; iii < argc; iii++) {
2587 if (argv[iii] != NULL) {
2594 demo.connection = hInstance;
2595 strncpy(demo.name, "tri", APP_NAME_STR_LEN);
2596 demo_create_window(&demo);
2597 demo_init_vk_swapchain(&demo);
2599 demo_prepare(&demo);
2601 done = false; // initialize loop condition variable
2602 /* main message loop*/
2604 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
2605 if (msg.message == WM_QUIT) // check for a quit message
2607 done = true; // if found, quit app
2609 /* Translate and dispatch to event queue*/
2610 TranslateMessage(&msg);
2611 DispatchMessage(&msg);
2613 RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT);
2616 demo_cleanup(&demo);
2618 return (int)msg.wParam;
2621 int main(const int argc, const char *argv[]) {
2624 demo_init(&demo, argc, argv);
2625 demo_create_window(&demo);
2626 demo_init_vk_swapchain(&demo);
2628 demo_prepare(&demo);
2631 demo_cleanup(&demo);
2633 return validation_error;