summaryrefslogtreecommitdiff
path: root/render/vulkan/swapchain.c
blob: 1247c9a97354c8437924b2a8a46faa5e69cc22d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "swapchain.h"
#include "vkassert.h"
#include "image.h"
#include <rune/core/logging.h>
#include <rune/core/alloc.h>
#include <rune/util/stubbed.h>

struct vkswapchain* create_swapchain(struct vksurface *surface, struct vkdev *dev) {
        struct vkswapchain *swapchain = rune_alloc(sizeof(struct vkswapchain));
        VkExtent2D sc_extent = {surface->width, surface->height};
        swapchain->max_frames = 2;
        get_swapchain_data(dev, &surface->handle);
        swapchain->format_khr = dev->scdata.formats[0];
        if (dev->scdata.capabilities.currentExtent.width != UINT32_MAX)
                sc_extent = dev->scdata.capabilities.currentExtent;

        VkExtent2D min = dev->scdata.capabilities.minImageExtent;
        VkExtent2D max = dev->scdata.capabilities.maxImageExtent;
        sc_extent.width = clamp(sc_extent.width, min.width, max.width);
        sc_extent.height = clamp(sc_extent.height, min.height, max.height);

        uint32_t img_count = dev->scdata.capabilities.minImageCount + 1;
        if (dev->scdata.capabilities.maxImageCount > 0 && img_count > dev->scdata.capabilities.maxImageCount)
                img_count = dev->scdata.capabilities.maxImageCount;

        VkSwapchainCreateInfoKHR cinfo;
        cinfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
        cinfo.surface = surface->handle;
        cinfo.minImageCount = img_count;
        cinfo.imageFormat = swapchain->format_khr.format;
        cinfo.imageColorSpace = swapchain->format_khr.colorSpace;
        cinfo.imageExtent = sc_extent;
        cinfo.imageArrayLayers = 1;
        cinfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
        cinfo.preTransform = dev->scdata.capabilities.currentTransform;
        cinfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
        cinfo.presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
        cinfo.clipped = VK_TRUE;
        cinfo.oldSwapchain = NULL;
        if (dev->gfx_index != dev->pres_index) {
                uint32_t qfams[] = {dev->gfx_index, dev->pres_index};
                cinfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
                cinfo.queueFamilyIndexCount = 2;
                cinfo.pQueueFamilyIndices = qfams;
        } else {
                cinfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
                cinfo.queueFamilyIndexCount = 0;
                cinfo.pQueueFamilyIndices = 0;
        }
        vkassert(vkCreateSwapchainKHR(dev->ldev, &cinfo, NULL, &swapchain->handle));
        vkassert(vkGetSwapchainImagesKHR(dev->ldev, swapchain->handle, &swapchain->img_count, NULL));

        swapchain->images = rune_alloc(sizeof(VkImage) * swapchain->img_count);
        swapchain->views = rune_alloc(sizeof(VkImageView) * swapchain->img_count);
        vkassert(vkGetSwapchainImagesKHR(dev->ldev, swapchain->handle, &swapchain->img_count, swapchain->images));

        VkImageViewCreateInfo vcinfo;
        for (uint32_t i = 0; i < swapchain->img_count; i++) {
                vcinfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
                vcinfo.image = swapchain->images[i];
                vcinfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
                vcinfo.format = swapchain->format;
                vcinfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
                vcinfo.subresourceRange.baseMipLevel = 0;
                vcinfo.subresourceRange.levelCount = 1;
                vcinfo.subresourceRange.baseArrayLayer = 0;
                vcinfo.subresourceRange.layerCount = 1;
                vkassert(vkCreateImageView(dev->ldev, &vcinfo, NULL, &swapchain->views[i]));
        }

        if (get_depth_format(dev) == 0) {
                log_output(LOG_FATAL, "Failed to find a supported image format");
                rune_abort();
        }

        swapchain->depth_attachment = create_vkimage(dev,
                                                     dev->depth_format,
                                                     surface->width,
                                                     surface->height,
                                                     VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
                                                     VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
                                                     VK_IMAGE_ASPECT_DEPTH_BIT,
                                                     1);
        swapchain->frame = 0;
        log_output(LOG_DEBUG, "Initialized swapchain");
        return swapchain;
}

void destroy_swapchain(struct vkswapchain *swapchain, struct vkdev *dev) {
        for (uint32_t i = 0; i < swapchain->img_count; i++)
                vkDestroyImageView(dev->ldev, swapchain->views[i], NULL);
        destroy_vkimage(swapchain->depth_attachment, dev);
        vkDestroySwapchainKHR(dev->ldev, swapchain->handle, NULL);
        rune_free(swapchain->images);
        rune_free(swapchain->views);
}

void vkswapchain_present(struct vkswapchain *swapchain, struct vkdev *dev) {
        VkPresentInfoKHR pinfo;
        pinfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
        pinfo.pNext = NULL;
        pinfo.waitSemaphoreCount = 1;
        pinfo.pWaitSemaphores = &swapchain->render_complete;
        pinfo.swapchainCount = 1;
        pinfo.pSwapchains = &swapchain->handle;
        pinfo.pImageIndices = &dev->pres_index;
        pinfo.pResults = NULL;

        VkResult res = vkQueuePresentKHR(dev->pres_queue, &pinfo);
        if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR)
                STUBBED("Recreate swapchain");
        else if (res != VK_SUCCESS)
                log_output(LOG_ERROR, "Vulkan error: %s", get_vkerr_str(res));

        swapchain->frame = (swapchain->frame + 1) % swapchain->max_frames;
}