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
22namespace {
23
24static const VkSurfaceFormatKHR surfaceFormats[] = {
25 { .format: VK_FORMAT_B8G8R8A8_UNORM, .colorSpace: VK_COLOR_SPACE_SRGB_NONLINEAR_KHR },
26 { .format: VK_FORMAT_B8G8R8A8_SRGB, .colorSpace: VK_COLOR_SPACE_SRGB_NONLINEAR_KHR },
27};
28
29static 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
41namespace vk {
42
43VkResult PresentImage::createImage(VkDevice device, const VkImageCreateInfo &createInfo)
44{
45 VkImage image;
46 VkResult status = vkCreateImage(device, pCreateInfo: &createInfo, pAllocator: nullptr, pImage: &image);
47 if(status != VK_SUCCESS)
48 {
49 return status;
50 }
51
52 this->image = Cast(object: image);
53
54 return status;
55}
56
57VkResult PresentImage::allocateAndBindImageMemory(VkDevice device, const VkMemoryAllocateInfo &allocateInfo)
58{
59 ASSERT(image);
60
61 VkDeviceMemory deviceMemory;
62 VkResult status = vkAllocateMemory(device, pAllocateInfo: &allocateInfo, pAllocator: nullptr, pMemory: &deviceMemory);
63 if(status != VK_SUCCESS)
64 {
65 release();
66 return status;
67 }
68
69 imageMemory = Cast(object: deviceMemory);
70 vkBindImageMemory(device, image: *image, memory: deviceMemory, memoryOffset: 0);
71 imageStatus = AVAILABLE;
72
73 return VK_SUCCESS;
74}
75
76void PresentImage::release()
77{
78 if(imageMemory)
79 {
80 vk::destroy(vkObject: static_cast<VkDeviceMemory>(*imageMemory), pAllocator: nullptr);
81 imageMemory = nullptr;
82 }
83
84 if(image)
85 {
86 vk::destroy(vkObject: static_cast<VkImage>(*image), pAllocator: nullptr);
87 image = nullptr;
88 }
89
90 imageStatus = NONEXISTENT;
91}
92
93VkImage PresentImage::asVkImage() const
94{
95 return image ? static_cast<VkImage>(*image) : VkImage({ VK_NULL_HANDLE });
96}
97
98uint32_t SurfaceKHR::getSurfaceFormatsCount(const void *pSurfaceInfoPNext) const
99{
100 return static_cast<uint32_t>(sizeof(surfaceFormats) / sizeof(surfaceFormats[0]));
101}
102
103VkResult 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(a: *pSurfaceFormatCount, b: 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
123uint32_t SurfaceKHR::getPresentModeCount() const
124{
125 return static_cast<uint32_t>(sizeof(presentModes) / sizeof(presentModes[0]));
126}
127
128VkResult 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(a: *pPresentModeCount, b: 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
148void SurfaceKHR::associateSwapchain(SwapchainKHR *swapchain)
149{
150 associatedSwapchain = swapchain;
151}
152
153void SurfaceKHR::disassociateSwapchain()
154{
155 associatedSwapchain = nullptr;
156}
157
158bool SurfaceKHR::hasAssociatedSwapchain()
159{
160 return (associatedSwapchain != nullptr);
161}
162
163VkResult 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(pSurfaceInfoPNext: nullptr, pSurfaceCapabilities: &capabilities, pSurfaceCapabilitiesPNext: nullptr);
178
179 pRects[0].offset = { .x: 0, .y: 0 };
180 pRects[0].extent = capabilities.currentExtent;
181 *pRectCount = 1;
182
183 return VK_SUCCESS;
184}
185
186void 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>(pNext: pSurfaceInfoPNext, sType: VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT);
225 ASSERT(presentMode != nullptr);
226
227 // No support for switching between present modes; i.e. each mode is only compatible with itself.
228 if(presentModeCompatibility->pPresentModes == nullptr)
229 {
230 presentModeCompatibility->presentModeCount = 1;
231 }
232 else if(presentModeCompatibility->presentModeCount >= 1)
233 {
234 presentModeCompatibility->pPresentModes[0] = presentMode->presentMode;
235 presentModeCompatibility->presentModeCount = 1;
236 }
237 break;
238 }
239 default:
240 UNSUPPORTED("pSurfaceCapabilities->pNext sType = %s", vk::Stringify(extInfo->sType).c_str());
241 break;
242 }
243 extInfo = extInfo->pNext;
244 }
245}
246
247} // namespace vk
248

source code of flutter_engine/third_party/swiftshader/src/WSI/VkSurfaceKHR.cpp