1 // Copyright 2018 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 "VkSurfaceKHR.hpp"
16
17 #include "Vulkan/VkDestroy.hpp"
18 #include "Vulkan/VkStringify.hpp"
19
20 #include <algorithm>
21
22 namespace {
23
24 static const VkSurfaceFormatKHR surfaceFormats[] = {
25 { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR },
26 { VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR },
27 };
28
29 static const VkPresentModeKHR presentModes[] = {
30 // FIXME(b/124265819): Make present modes behave correctly. Currently we use XPutImage
31 // with no synchronization, which behaves more like VK_PRESENT_MODE_IMMEDIATE_KHR. We
32 // should convert to using the Present extension, which allows us to request presentation
33 // at particular msc values. Will need a similar solution on Windows - possibly interact
34 // with DXGI directly.
35 VK_PRESENT_MODE_FIFO_KHR,
36 VK_PRESENT_MODE_MAILBOX_KHR,
37 };
38
39 } // namespace
40
41 namespace vk {
42
createImage(VkDevice device,const VkImageCreateInfo & createInfo)43 VkResult PresentImage::createImage(VkDevice device, const VkImageCreateInfo &createInfo)
44 {
45 VkImage image;
46 VkResult status = vkCreateImage(device, &createInfo, nullptr, &image);
47 if(status != VK_SUCCESS)
48 {
49 return status;
50 }
51
52 this->image = Cast(image);
53
54 return status;
55 }
56
allocateAndBindImageMemory(VkDevice device,const VkMemoryAllocateInfo & allocateInfo)57 VkResult PresentImage::allocateAndBindImageMemory(VkDevice device, const VkMemoryAllocateInfo &allocateInfo)
58 {
59 ASSERT(image);
60
61 VkDeviceMemory deviceMemory;
62 VkResult status = vkAllocateMemory(device, &allocateInfo, nullptr, &deviceMemory);
63 if(status != VK_SUCCESS)
64 {
65 release();
66 return status;
67 }
68
69 imageMemory = Cast(deviceMemory);
70 vkBindImageMemory(device, *image, deviceMemory, 0);
71 imageStatus = AVAILABLE;
72
73 return VK_SUCCESS;
74 }
75
release()76 void PresentImage::release()
77 {
78 if(imageMemory)
79 {
80 vk::destroy(static_cast<VkDeviceMemory>(*imageMemory), nullptr);
81 imageMemory = nullptr;
82 }
83
84 if(image)
85 {
86 vk::destroy(static_cast<VkImage>(*image), nullptr);
87 image = nullptr;
88 }
89
90 imageStatus = NONEXISTENT;
91 }
92
asVkImage() const93 VkImage PresentImage::asVkImage() const
94 {
95 return image ? static_cast<VkImage>(*image) : VkImage({ VK_NULL_HANDLE });
96 }
97
getSurfaceFormatsCount(const void * pSurfaceInfoPNext) const98 uint32_t SurfaceKHR::getSurfaceFormatsCount(const void *pSurfaceInfoPNext) const
99 {
100 return static_cast<uint32_t>(sizeof(surfaceFormats) / sizeof(surfaceFormats[0]));
101 }
102
getSurfaceFormats(const void * pSurfaceInfoPNext,uint32_t * pSurfaceFormatCount,VkSurfaceFormat2KHR * pSurfaceFormats) const103 VkResult SurfaceKHR::getSurfaceFormats(const void *pSurfaceInfoPNext, uint32_t *pSurfaceFormatCount, VkSurfaceFormat2KHR *pSurfaceFormats) const
104 {
105 uint32_t count = getSurfaceFormatsCount(pSurfaceInfoPNext);
106
107 uint32_t i;
108 for(i = 0; i < std::min(*pSurfaceFormatCount, count); i++)
109 {
110 pSurfaceFormats[i].surfaceFormat = surfaceFormats[i];
111 }
112
113 *pSurfaceFormatCount = i;
114
115 if(*pSurfaceFormatCount < count)
116 {
117 return VK_INCOMPLETE;
118 }
119
120 return VK_SUCCESS;
121 }
122
getPresentModeCount() const123 uint32_t SurfaceKHR::getPresentModeCount() const
124 {
125 return static_cast<uint32_t>(sizeof(presentModes) / sizeof(presentModes[0]));
126 }
127
getPresentModes(uint32_t * pPresentModeCount,VkPresentModeKHR * pPresentModes) const128 VkResult SurfaceKHR::getPresentModes(uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes) const
129 {
130 uint32_t count = getPresentModeCount();
131
132 uint32_t i;
133 for(i = 0; i < std::min(*pPresentModeCount, count); i++)
134 {
135 pPresentModes[i] = presentModes[i];
136 }
137
138 *pPresentModeCount = i;
139
140 if(*pPresentModeCount < count)
141 {
142 return VK_INCOMPLETE;
143 }
144
145 return VK_SUCCESS;
146 }
147
associateSwapchain(SwapchainKHR * swapchain)148 void SurfaceKHR::associateSwapchain(SwapchainKHR *swapchain)
149 {
150 associatedSwapchain = swapchain;
151 }
152
disassociateSwapchain()153 void SurfaceKHR::disassociateSwapchain()
154 {
155 associatedSwapchain = nullptr;
156 }
157
hasAssociatedSwapchain()158 bool SurfaceKHR::hasAssociatedSwapchain()
159 {
160 return (associatedSwapchain != nullptr);
161 }
162
getPresentRectangles(uint32_t * pRectCount,VkRect2D * pRects) const163 VkResult SurfaceKHR::getPresentRectangles(uint32_t *pRectCount, VkRect2D *pRects) const
164 {
165 if(!pRects)
166 {
167 *pRectCount = 1;
168 return VK_SUCCESS;
169 }
170
171 if(*pRectCount < 1)
172 {
173 return VK_INCOMPLETE;
174 }
175
176 VkSurfaceCapabilitiesKHR capabilities;
177 getSurfaceCapabilities(nullptr, &capabilities, nullptr);
178
179 pRects[0].offset = { 0, 0 };
180 pRects[0].extent = capabilities.currentExtent;
181 *pRectCount = 1;
182
183 return VK_SUCCESS;
184 }
185
setCommonSurfaceCapabilities(const void * pSurfaceInfoPNext,VkSurfaceCapabilitiesKHR * pSurfaceCapabilities,void * pSurfaceCapabilitiesPNext)186 void SurfaceKHR::setCommonSurfaceCapabilities(const void *pSurfaceInfoPNext, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities, void *pSurfaceCapabilitiesPNext)
187 {
188 pSurfaceCapabilities->minImageCount = 1;
189 pSurfaceCapabilities->maxImageCount = 0;
190
191 pSurfaceCapabilities->maxImageArrayLayers = 1;
192
193 pSurfaceCapabilities->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
194 pSurfaceCapabilities->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
195 pSurfaceCapabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
196 pSurfaceCapabilities->supportedUsageFlags =
197 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
198 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
199 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
200 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
201 VK_IMAGE_USAGE_SAMPLED_BIT |
202 VK_IMAGE_USAGE_STORAGE_BIT;
203
204 auto *extInfo = reinterpret_cast<VkBaseOutStructure *>(pSurfaceCapabilitiesPNext);
205 while(extInfo)
206 {
207 switch(extInfo->sType)
208 {
209 case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT:
210 {
211 // Supported scaling is per present mode, but currently that's identical for all present modes.
212 ASSERT(vk::GetExtendedStruct<VkSurfacePresentModeEXT>(pSurfaceInfoPNext, VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT) != nullptr);
213 VkSurfacePresentScalingCapabilitiesEXT *presentScalingCapabilities = reinterpret_cast<VkSurfacePresentScalingCapabilitiesEXT *>(extInfo);
214 presentScalingCapabilities->supportedPresentScaling = 0;
215 presentScalingCapabilities->supportedPresentGravityX = 0;
216 presentScalingCapabilities->supportedPresentGravityY = 0;
217 presentScalingCapabilities->minScaledImageExtent = pSurfaceCapabilities->minImageExtent;
218 presentScalingCapabilities->maxScaledImageExtent = pSurfaceCapabilities->maxImageExtent;
219 break;
220 }
221 case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT:
222 {
223 VkSurfacePresentModeCompatibilityEXT *presentModeCompatibility = reinterpret_cast<VkSurfacePresentModeCompatibilityEXT *>(extInfo);
224 const auto *presentMode = vk::GetExtendedStruct<VkSurfacePresentModeEXT>(pSurfaceInfoPNext, VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT);
225 ASSERT(presentMode != nullptr);
226
227 // Present mode is ignored, so FIFO and MAILBOX are compatible.
228 if(presentModeCompatibility->pPresentModes == nullptr)
229 {
230 presentModeCompatibility->presentModeCount = 2;
231 }
232 else if(presentModeCompatibility->presentModeCount == 1)
233 {
234 presentModeCompatibility->pPresentModes[0] = presentMode->presentMode;
235 presentModeCompatibility->presentModeCount = 1;
236 }
237 else if(presentModeCompatibility->presentModeCount > 1)
238 {
239 presentModeCompatibility->pPresentModes[0] = presentModes[0];
240 presentModeCompatibility->pPresentModes[1] = presentModes[1];
241 presentModeCompatibility->presentModeCount = 2;
242 }
243 break;
244 }
245 default:
246 UNSUPPORTED("pSurfaceCapabilities->pNext sType = %s", vk::Stringify(extInfo->sType).c_str());
247 break;
248 }
249 extInfo = extInfo->pNext;
250 }
251 }
252
253 } // namespace vk
254