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 | |
25 | namespace vk |
26 | { |
27 | |
28 | SwapchainKHR::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 | |
37 | void 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(¤tImage); |
45 | currentImage.clear(); |
46 | } |
47 | } |
48 | |
49 | if(!retired) |
50 | { |
51 | surface->disassociateSwapchain(); |
52 | } |
53 | |
54 | vk::deallocate(images, pAllocator); |
55 | } |
56 | |
57 | size_t SwapchainKHR::ComputeRequiredAllocationSize(const VkSwapchainCreateInfoKHR *pCreateInfo) |
58 | { |
59 | return pCreateInfo->minImageCount * sizeof(PresentImage); |
60 | } |
61 | |
62 | void 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(¤tImage); |
75 | currentImage.clear(); |
76 | } |
77 | } |
78 | } |
79 | } |
80 | |
81 | void SwapchainKHR::resetImages() |
82 | { |
83 | for(uint32_t i = 0; i < imageCount; i++) |
84 | { |
85 | images[i].clear(); |
86 | } |
87 | } |
88 | |
89 | VkResult 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(¤tImage); |
146 | } |
147 | |
148 | return VK_SUCCESS; |
149 | } |
150 | |
151 | uint32_t SwapchainKHR::getImageCount() const |
152 | { |
153 | return imageCount; |
154 | } |
155 | |
156 | VkResult 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 | |
174 | VkResult 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 | |
201 | VkResult 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 | } |