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 }
46 }
47
48 if(!retired)
49 {
50 surface->disassociateSwapchain();
51 }
52
53 vk::freeHostMemory(images, pAllocator);
54 }
55
ComputeRequiredAllocationSize(const VkSwapchainCreateInfoKHR * pCreateInfo)56 size_t SwapchainKHR::ComputeRequiredAllocationSize(const VkSwapchainCreateInfoKHR *pCreateInfo)
57 {
58 return pCreateInfo->minImageCount * sizeof(PresentImage);
59 }
60
retire()61 void SwapchainKHR::retire()
62 {
63 if(!retired)
64 {
65 retired = true;
66 surface->disassociateSwapchain();
67
68 for(uint32_t i = 0; i < imageCount; i++)
69 {
70 PresentImage ¤tImage = images[i];
71 if(currentImage.isAvailable())
72 {
73 surface->detachImage(¤tImage);
74 currentImage.release();
75 }
76 }
77 }
78 }
79
resetImages()80 void SwapchainKHR::resetImages()
81 {
82 for(uint32_t i = 0; i < imageCount; i++)
83 {
84 images[i].release();
85 }
86 }
87
createImages(VkDevice device,const VkSwapchainCreateInfoKHR * pCreateInfo)88 VkResult SwapchainKHR::createImages(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo)
89 {
90 resetImages();
91
92 VkImageCreateInfo imageInfo = {};
93 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
94
95 if(pCreateInfo->flags & VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR)
96 {
97 imageInfo.flags |= VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT;
98 }
99
100 if(pCreateInfo->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR)
101 {
102 imageInfo.flags |= VK_IMAGE_CREATE_PROTECTED_BIT;
103 }
104
105 if(pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR)
106 {
107 imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
108 }
109
110 imageInfo.imageType = VK_IMAGE_TYPE_2D;
111 imageInfo.format = pCreateInfo->imageFormat;
112 imageInfo.extent.height = pCreateInfo->imageExtent.height;
113 imageInfo.extent.width = pCreateInfo->imageExtent.width;
114 imageInfo.extent.depth = 1;
115 imageInfo.mipLevels = 1;
116 imageInfo.arrayLayers = pCreateInfo->imageArrayLayers;
117 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
118 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
119 imageInfo.usage = pCreateInfo->imageUsage;
120 imageInfo.sharingMode = pCreateInfo->imageSharingMode;
121 imageInfo.pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices;
122 imageInfo.queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount;
123 imageInfo.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
124
125 VkMemoryAllocateInfo allocInfo = {};
126 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
127 allocInfo.allocationSize = 0;
128 allocInfo.memoryTypeIndex = 0;
129
130 VkResult status;
131 for(uint32_t i = 0; i < imageCount; i++)
132 {
133 PresentImage ¤tImage = images[i];
134
135 status = currentImage.createImage(device, imageInfo);
136 if(status != VK_SUCCESS)
137 {
138 return status;
139 }
140
141 allocInfo.allocationSize = currentImage.getImage()->getMemoryRequirements().size;
142
143 status = currentImage.allocateAndBindImageMemory(device, allocInfo);
144 if(status != VK_SUCCESS)
145 {
146 return status;
147 }
148
149 surface->attachImage(¤tImage);
150 }
151
152 return VK_SUCCESS;
153 }
154
getImageCount() const155 uint32_t SwapchainKHR::getImageCount() const
156 {
157 return imageCount;
158 }
159
getImages(uint32_t * pSwapchainImageCount,VkImage * pSwapchainImages) const160 VkResult SwapchainKHR::getImages(uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) const
161 {
162 uint32_t i;
163 for(i = 0; i < std::min(*pSwapchainImageCount, imageCount); i++)
164 {
165 pSwapchainImages[i] = images[i].asVkImage();
166 }
167
168 *pSwapchainImageCount = i;
169
170 if(*pSwapchainImageCount < imageCount)
171 {
172 return VK_INCOMPLETE;
173 }
174
175 return VK_SUCCESS;
176 }
177
getNextImage(uint64_t timeout,BinarySemaphore * semaphore,Fence * fence,uint32_t * pImageIndex)178 VkResult SwapchainKHR::getNextImage(uint64_t timeout, BinarySemaphore *semaphore, Fence *fence, uint32_t *pImageIndex)
179 {
180 for(uint32_t i = 0; i < imageCount; i++)
181 {
182 PresentImage ¤tImage = images[i];
183 if(currentImage.isAvailable())
184 {
185 currentImage.setStatus(DRAWING);
186 *pImageIndex = i;
187
188 if(semaphore)
189 {
190 semaphore->signal();
191 }
192
193 if(fence)
194 {
195 fence->complete();
196 }
197
198 return VK_SUCCESS;
199 }
200 }
201
202 return (timeout > 0) ? VK_TIMEOUT : VK_NOT_READY;
203 }
204
present(uint32_t index)205 VkResult SwapchainKHR::present(uint32_t index)
206 {
207 auto &image = images[index];
208 image.setStatus(PRESENTING);
209 VkResult result = surface->present(&image);
210 image.setStatus(AVAILABLE);
211
212 if(retired)
213 {
214 surface->detachImage(&image);
215 image.release();
216 }
217
218 return result;
219 }
220
221 } // namespace vk