1// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "VkSwapchainKHR.hpp"
16
17#include "Vulkan/VkDeviceMemory.hpp"
18#include "Vulkan/VkFence.hpp"
19#include "Vulkan/VkImage.hpp"
20#include "Vulkan/VkSemaphore.hpp"
21
22#include <algorithm>
23#include <cstring>
24
25namespace vk
26{
27
28SwapchainKHR::SwapchainKHR(const VkSwapchainCreateInfoKHR *pCreateInfo, void *mem) :
29 surface(vk::Cast(pCreateInfo->surface)),
30 images(reinterpret_cast<PresentImage*>(mem)),
31 imageCount(pCreateInfo->minImageCount),
32 retired(false)
33{
34 memset(reinterpret_cast<void*>(images), 0, imageCount * sizeof(PresentImage));
35}
36
37void SwapchainKHR::destroy(const VkAllocationCallbacks *pAllocator)
38{
39 for(uint32_t i = 0; i < imageCount; i++)
40 {
41 PresentImage& currentImage = images[i];
42 if(currentImage.exists())
43 {
44 surface->detachImage(&currentImage);
45 currentImage.clear();
46 }
47 }
48
49 if(!retired)
50 {
51 surface->disassociateSwapchain();
52 }
53
54 vk::deallocate(images, pAllocator);
55}
56
57size_t SwapchainKHR::ComputeRequiredAllocationSize(const VkSwapchainCreateInfoKHR *pCreateInfo)
58{
59 return pCreateInfo->minImageCount * sizeof(PresentImage);
60}
61
62void SwapchainKHR::retire()
63{
64 if(!retired)
65 {
66 retired = true;
67 surface->disassociateSwapchain();
68
69 for(uint32_t i = 0; i < imageCount; i++)
70 {
71 PresentImage& currentImage = images[i];
72 if(currentImage.isAvailable())
73 {
74 surface->detachImage(&currentImage);
75 currentImage.clear();
76 }
77 }
78 }
79}
80
81void SwapchainKHR::resetImages()
82{
83 for(uint32_t i = 0; i < imageCount; i++)
84 {
85 images[i].clear();
86 }
87}
88
89VkResult SwapchainKHR::createImages(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo)
90{
91 resetImages();
92
93 VkImageCreateInfo imageInfo = {};
94 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
95
96 if(pCreateInfo->flags & VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR)
97 {
98 imageInfo.flags |= VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT;
99 }
100
101 if(pCreateInfo->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR)
102 {
103 imageInfo.flags |= VK_IMAGE_CREATE_PROTECTED_BIT;
104 }
105
106 imageInfo.imageType = VK_IMAGE_TYPE_2D;
107 imageInfo.format = pCreateInfo->imageFormat;
108 imageInfo.extent.height = pCreateInfo->imageExtent.height;
109 imageInfo.extent.width = pCreateInfo->imageExtent.width;
110 imageInfo.extent.depth = 1;
111 imageInfo.mipLevels = 1;
112 imageInfo.arrayLayers = pCreateInfo->imageArrayLayers;
113 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
114 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
115 imageInfo.usage = pCreateInfo->imageUsage;
116 imageInfo.sharingMode = pCreateInfo->imageSharingMode;
117 imageInfo.pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices;
118 imageInfo.queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount;
119 imageInfo.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
120
121 VkMemoryAllocateInfo allocInfo = {};
122 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
123 allocInfo.allocationSize = 0;
124 allocInfo.memoryTypeIndex = 0;
125
126 VkResult status;
127 for(uint32_t i = 0; i < imageCount; i++)
128 {
129 PresentImage& currentImage = images[i];
130
131 status = currentImage.allocateImage(device, imageInfo);
132 if(status != VK_SUCCESS)
133 {
134 return status;
135 }
136
137 allocInfo.allocationSize = currentImage.getImage()->getMemoryRequirements().size;
138
139 status = currentImage.allocateAndBindImageMemory(device, allocInfo);
140 if(status != VK_SUCCESS)
141 {
142 return status;
143 }
144
145 surface->attachImage(&currentImage);
146 }
147
148 return VK_SUCCESS;
149}
150
151uint32_t SwapchainKHR::getImageCount() const
152{
153 return imageCount;
154}
155
156VkResult SwapchainKHR::getImages(uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) const
157{
158 uint32_t i;
159 for(i = 0; i < std::min(*pSwapchainImageCount, imageCount); i++)
160 {
161 pSwapchainImages[i] = images[i].asVkImage();
162 }
163
164 *pSwapchainImageCount = i;
165
166 if(*pSwapchainImageCount < imageCount)
167 {
168 return VK_INCOMPLETE;
169 }
170
171 return VK_SUCCESS;
172}
173
174VkResult SwapchainKHR::getNextImage(uint64_t timeout, Semaphore* semaphore, Fence* fence, uint32_t *pImageIndex)
175{
176 for(uint32_t i = 0; i < imageCount; i++)
177 {
178 PresentImage& currentImage = images[i];
179 if(currentImage.isAvailable())
180 {
181 currentImage.setStatus(DRAWING);
182 *pImageIndex = i;
183
184 if(semaphore)
185 {
186 semaphore->signal();
187 }
188
189 if(fence)
190 {
191 fence->complete();
192 }
193
194 return VK_SUCCESS;
195 }
196 }
197
198 return VK_NOT_READY;
199}
200
201VkResult SwapchainKHR::present(uint32_t index)
202{
203 auto& image = images[index];
204 image.setStatus(PRESENTING);
205 VkResult result = surface->present(&image);
206 image.setStatus(AVAILABLE);
207
208 if(retired)
209 {
210 surface->detachImage(&image);
211 image.clear();
212 }
213
214 return result;
215}
216
217}