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.clear();
45 }
46 }
47
48 if(!retired)
49 {
50 surface->disassociateSwapchain();
51 }
52
53 vk::deallocate(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.clear();
75 }
76 }
77 }
78 }
79
resetImages()80 void SwapchainKHR::resetImages()
81 {
82 for(uint32_t i = 0; i < imageCount; i++)
83 {
84 images[i].clear();
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 imageInfo.imageType = VK_IMAGE_TYPE_2D;
106 imageInfo.format = pCreateInfo->imageFormat;
107 imageInfo.extent.height = pCreateInfo->imageExtent.height;
108 imageInfo.extent.width = pCreateInfo->imageExtent.width;
109 imageInfo.extent.depth = 1;
110 imageInfo.mipLevels = 1;
111 imageInfo.arrayLayers = pCreateInfo->imageArrayLayers;
112 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
113 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
114 imageInfo.usage = pCreateInfo->imageUsage;
115 imageInfo.sharingMode = pCreateInfo->imageSharingMode;
116 imageInfo.pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices;
117 imageInfo.queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount;
118 imageInfo.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
119
120 VkMemoryAllocateInfo allocInfo = {};
121 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
122 allocInfo.allocationSize = 0;
123 allocInfo.memoryTypeIndex = 0;
124
125 VkResult status;
126 for(uint32_t i = 0; i < imageCount; i++)
127 {
128 PresentImage ¤tImage = images[i];
129
130 status = currentImage.allocateImage(device, imageInfo);
131 if(status != VK_SUCCESS)
132 {
133 return status;
134 }
135
136 allocInfo.allocationSize = currentImage.getImage()->getMemoryRequirements().size;
137
138 status = currentImage.allocateAndBindImageMemory(device, allocInfo);
139 if(status != VK_SUCCESS)
140 {
141 return status;
142 }
143
144 surface->attachImage(¤tImage);
145 }
146
147 return VK_SUCCESS;
148 }
149
getImageCount() const150 uint32_t SwapchainKHR::getImageCount() const
151 {
152 return imageCount;
153 }
154
getImages(uint32_t * pSwapchainImageCount,VkImage * pSwapchainImages) const155 VkResult SwapchainKHR::getImages(uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) const
156 {
157 uint32_t i;
158 for(i = 0; i < std::min(*pSwapchainImageCount, imageCount); i++)
159 {
160 pSwapchainImages[i] = images[i].asVkImage();
161 }
162
163 *pSwapchainImageCount = i;
164
165 if(*pSwapchainImageCount < imageCount)
166 {
167 return VK_INCOMPLETE;
168 }
169
170 return VK_SUCCESS;
171 }
172
getNextImage(uint64_t timeout,Semaphore * semaphore,Fence * fence,uint32_t * pImageIndex)173 VkResult SwapchainKHR::getNextImage(uint64_t timeout, Semaphore *semaphore, Fence *fence, uint32_t *pImageIndex)
174 {
175 for(uint32_t i = 0; i < imageCount; i++)
176 {
177 PresentImage ¤tImage = images[i];
178 if(currentImage.isAvailable())
179 {
180 currentImage.setStatus(DRAWING);
181 *pImageIndex = i;
182
183 if(semaphore)
184 {
185 semaphore->signal();
186 }
187
188 if(fence)
189 {
190 fence->complete();
191 }
192
193 return VK_SUCCESS;
194 }
195 }
196
197 return VK_NOT_READY;
198 }
199
present(uint32_t index)200 VkResult SwapchainKHR::present(uint32_t index)
201 {
202 auto &image = images[index];
203 image.setStatus(PRESENTING);
204 VkResult result = surface->present(&image);
205 image.setStatus(AVAILABLE);
206
207 if(retired)
208 {
209 surface->detachImage(&image);
210 image.clear();
211 }
212
213 return result;
214 }
215
216 } // namespace vk