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
SwapchainKHR(const VkSwapchainCreateInfoKHR * pCreateInfo,void * mem)27 SwapchainKHR::SwapchainKHR(const VkSwapchainCreateInfoKHR *pCreateInfo, void *mem)
28 : surface(vk::Cast(pCreateInfo->surface))
29 , images(reinterpret_cast<PresentImage *>(mem))
30 , imageCount(pCreateInfo->minImageCount)
31 , retired(false)
32 {
33 memset(reinterpret_cast<void *>(images), 0, imageCount * sizeof(PresentImage));
34 }
35
destroy(const VkAllocationCallbacks * pAllocator)36 void SwapchainKHR::destroy(const VkAllocationCallbacks *pAllocator)
37 {
38 for(uint32_t i = 0; i < imageCount; i++)
39 {
40 PresentImage ¤tImage = images[i];
41 if(currentImage.exists())
42 {
43 surface->detachImage(¤tImage);
44 currentImage.release();
45 surface->releaseImageMemory(¤tImage);
46 }
47 }
48
49 if(!retired)
50 {
51 surface->disassociateSwapchain();
52 }
53
54 vk::freeHostMemory(images, pAllocator);
55 }
56
ComputeRequiredAllocationSize(const VkSwapchainCreateInfoKHR * pCreateInfo)57 size_t SwapchainKHR::ComputeRequiredAllocationSize(const VkSwapchainCreateInfoKHR *pCreateInfo)
58 {
59 return pCreateInfo->minImageCount * sizeof(PresentImage);
60 }
61
retire()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 ¤tImage = images[i];
72 if(currentImage.isAvailable())
73 {
74 surface->detachImage(¤tImage);
75 currentImage.release();
76 }
77 }
78 }
79 }
80
resetImages()81 void SwapchainKHR::resetImages()
82 {
83 for(uint32_t i = 0; i < imageCount; i++)
84 {
85 images[i].release();
86 }
87 }
88
createImages(VkDevice device,const VkSwapchainCreateInfoKHR * pCreateInfo)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 if(pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR)
107 {
108 imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
109 }
110
111 imageInfo.imageType = VK_IMAGE_TYPE_2D;
112 imageInfo.format = pCreateInfo->imageFormat;
113 imageInfo.extent.height = pCreateInfo->imageExtent.height;
114 imageInfo.extent.width = pCreateInfo->imageExtent.width;
115 imageInfo.extent.depth = 1;
116 imageInfo.mipLevels = 1;
117 imageInfo.arrayLayers = pCreateInfo->imageArrayLayers;
118 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
119 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
120 imageInfo.usage = pCreateInfo->imageUsage;
121 imageInfo.sharingMode = pCreateInfo->imageSharingMode;
122 imageInfo.pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices;
123 imageInfo.queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount;
124 imageInfo.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
125
126 VkMemoryAllocateInfo allocInfo = {};
127 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
128 allocInfo.allocationSize = 0;
129 allocInfo.memoryTypeIndex = 0;
130
131 VkResult status;
132 for(uint32_t i = 0; i < imageCount; i++)
133 {
134 PresentImage ¤tImage = images[i];
135
136 status = currentImage.createImage(device, imageInfo);
137 if(status != VK_SUCCESS)
138 {
139 return status;
140 }
141
142 allocInfo.allocationSize = currentImage.getImage()->getMemoryRequirements().size;
143 void* memory = vk::Cast(pCreateInfo->surface)->allocateImageMemory(¤tImage, allocInfo);
144
145 VkImportMemoryHostPointerInfoEXT importMemoryHostPointerInfo = {};
146 if (memory)
147 {
148 importMemoryHostPointerInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT;
149 importMemoryHostPointerInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT;
150 importMemoryHostPointerInfo.pHostPointer = memory;
151 allocInfo.pNext = &importMemoryHostPointerInfo;
152 }
153
154 status = currentImage.allocateAndBindImageMemory(device, allocInfo);
155 if(status != VK_SUCCESS)
156 {
157 vk::Cast(pCreateInfo->surface)->releaseImageMemory(¤tImage);
158 return status;
159 }
160
161 surface->attachImage(¤tImage);
162 }
163
164 return VK_SUCCESS;
165 }
166
getImageCount() const167 uint32_t SwapchainKHR::getImageCount() const
168 {
169 return imageCount;
170 }
171
getImages(uint32_t * pSwapchainImageCount,VkImage * pSwapchainImages) const172 VkResult SwapchainKHR::getImages(uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) const
173 {
174 uint32_t i;
175 for(i = 0; i < std::min(*pSwapchainImageCount, imageCount); i++)
176 {
177 pSwapchainImages[i] = images[i].asVkImage();
178 }
179
180 *pSwapchainImageCount = i;
181
182 if(*pSwapchainImageCount < imageCount)
183 {
184 return VK_INCOMPLETE;
185 }
186
187 return VK_SUCCESS;
188 }
189
getNextImage(uint64_t timeout,BinarySemaphore * semaphore,Fence * fence,uint32_t * pImageIndex)190 VkResult SwapchainKHR::getNextImage(uint64_t timeout, BinarySemaphore *semaphore, Fence *fence, uint32_t *pImageIndex)
191 {
192 for(uint32_t i = 0; i < imageCount; i++)
193 {
194 PresentImage ¤tImage = images[i];
195 if(currentImage.isAvailable())
196 {
197 currentImage.setStatus(DRAWING);
198 *pImageIndex = i;
199
200 if(semaphore)
201 {
202 semaphore->signal();
203 }
204
205 if(fence)
206 {
207 fence->complete();
208 }
209
210 return VK_SUCCESS;
211 }
212 }
213
214 return (timeout > 0) ? VK_TIMEOUT : VK_NOT_READY;
215 }
216
present(uint32_t index)217 VkResult SwapchainKHR::present(uint32_t index)
218 {
219 auto &image = images[index];
220 image.setStatus(PRESENTING);
221 VkResult result = surface->present(&image);
222
223 releaseImage(index);
224 return result;
225 }
226
releaseImages(uint32_t imageIndexCount,const uint32_t * pImageIndices)227 VkResult SwapchainKHR::releaseImages(uint32_t imageIndexCount, const uint32_t *pImageIndices)
228 {
229 for(uint32_t i = 0; i < imageIndexCount; ++i)
230 {
231 releaseImage(pImageIndices[i]);
232 }
233 return VK_SUCCESS;
234 }
235
releaseImage(uint32_t index)236 void SwapchainKHR::releaseImage(uint32_t index)
237 {
238 auto &image = images[index];
239 image.setStatus(AVAILABLE);
240
241 if(retired)
242 {
243 surface->detachImage(&image);
244 image.release();
245 surface->releaseImageMemory(&image);
246 }
247 }
248 } // namespace vk
249