• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "SwapChainStateVk.h"
2 
3 #include <cinttypes>
4 #include <unordered_set>
5 
6 #include "host-common/GfxstreamFatalError.h"
7 #include "host-common/logging.h"
8 #include "vulkan/vk_enum_string_helper.h"
9 #include "vulkan/vk_util.h"
10 
11 using emugl::ABORT_REASON_OTHER;
12 using emugl::FatalError;
13 
14 #define SWAPCHAINSTATE_VK_ERROR(fmt, ...)                                                     \
15     do {                                                                                      \
16         fprintf(stderr, "%s(%s:%d): " fmt "\n", __func__, __FILE__, __LINE__, ##__VA_ARGS__); \
17         fflush(stderr);                                                                       \
18     } while (0)
19 
20 namespace {
21 
swap(SwapchainCreateInfoWrapper & a,SwapchainCreateInfoWrapper & b)22 void swap(SwapchainCreateInfoWrapper& a, SwapchainCreateInfoWrapper& b) {
23     std::swap(a.mQueueFamilyIndices, b.mQueueFamilyIndices);
24     std::swap(a.mCreateInfo, b.mCreateInfo);
25     // The C++ spec guarantees that after std::swap is called, all iterators and references of the
26     // container remain valid, and the past-the-end iterator is invalidated. Therefore, no need to
27     // reset the VkSwapchainCreateInfoKHR::pQueueFamilyIndices.
28 }
29 
30 }  // namespace
31 
SwapchainCreateInfoWrapper(const VkSwapchainCreateInfoKHR & createInfo)32 SwapchainCreateInfoWrapper::SwapchainCreateInfoWrapper(const VkSwapchainCreateInfoKHR& createInfo)
33     : mCreateInfo(createInfo) {
34     if (createInfo.pNext) {
35         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
36             << "VkSwapchainCreateInfoKHR with pNext in the chain is not supported.";
37     }
38 
39     if (createInfo.pQueueFamilyIndices && (createInfo.queueFamilyIndexCount > 0)) {
40         setQueueFamilyIndices(std::vector<uint32_t>(
41             createInfo.pQueueFamilyIndices,
42             createInfo.pQueueFamilyIndices + createInfo.queueFamilyIndexCount));
43     } else {
44         setQueueFamilyIndices({});
45     }
46 }
47 
SwapchainCreateInfoWrapper(const SwapchainCreateInfoWrapper & other)48 SwapchainCreateInfoWrapper::SwapchainCreateInfoWrapper(const SwapchainCreateInfoWrapper& other)
49     : mCreateInfo(other.mCreateInfo) {
50     if (other.mCreateInfo.pNext) {
51         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
52             << "VkSwapchainCreateInfoKHR with pNext in the chain is not supported.";
53     }
54     setQueueFamilyIndices(other.mQueueFamilyIndices);
55 }
56 
operator =(const SwapchainCreateInfoWrapper & other)57 SwapchainCreateInfoWrapper& SwapchainCreateInfoWrapper::operator=(
58     const SwapchainCreateInfoWrapper& other) {
59     SwapchainCreateInfoWrapper tmp(other);
60     swap(*this, tmp);
61     return *this;
62 }
63 
setQueueFamilyIndices(const std::vector<uint32_t> & queueFamilyIndices)64 void SwapchainCreateInfoWrapper::setQueueFamilyIndices(
65     const std::vector<uint32_t>& queueFamilyIndices) {
66     mQueueFamilyIndices = queueFamilyIndices;
67     mCreateInfo.queueFamilyIndexCount = static_cast<uint32_t>(mQueueFamilyIndices.size());
68     if (mQueueFamilyIndices.empty()) {
69         mCreateInfo.pQueueFamilyIndices = nullptr;
70     } else {
71         mCreateInfo.pQueueFamilyIndices = queueFamilyIndices.data();
72     }
73 }
74 
SwapChainStateVk(const goldfish_vk::VulkanDispatch & vk,VkDevice vkDevice,const VkSwapchainCreateInfoKHR & swapChainCi)75 SwapChainStateVk::SwapChainStateVk(const goldfish_vk::VulkanDispatch &vk, VkDevice vkDevice,
76                                    const VkSwapchainCreateInfoKHR &swapChainCi)
77     : m_vk(vk),
78       m_vkDevice(vkDevice),
79       m_vkSwapChain(VK_NULL_HANDLE),
80       m_vkImages(0),
81       m_vkImageViews(0) {
82     VK_CHECK(m_vk.vkCreateSwapchainKHR(m_vkDevice, &swapChainCi, nullptr, &m_vkSwapChain));
83     uint32_t imageCount = 0;
84     VK_CHECK(m_vk.vkGetSwapchainImagesKHR(m_vkDevice, m_vkSwapChain, &imageCount, nullptr));
85     m_vkImages.resize(imageCount);
86     VK_CHECK(
87         m_vk.vkGetSwapchainImagesKHR(m_vkDevice, m_vkSwapChain, &imageCount, m_vkImages.data()));
88     for (auto i = 0; i < m_vkImages.size(); i++) {
89         VkImageViewCreateInfo imageViewCi = {
90             .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
91             .image = m_vkImages[i],
92             .viewType = VK_IMAGE_VIEW_TYPE_2D,
93             .format = k_vkFormat,
94             .components = {.r = VK_COMPONENT_SWIZZLE_IDENTITY,
95                            .g = VK_COMPONENT_SWIZZLE_IDENTITY,
96                            .b = VK_COMPONENT_SWIZZLE_IDENTITY,
97                            .a = VK_COMPONENT_SWIZZLE_IDENTITY},
98             .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
99                                  .baseMipLevel = 0,
100                                  .levelCount = 1,
101                                  .baseArrayLayer = 0,
102                                  .layerCount = 1}};
103         VkImageView vkImageView;
104         VK_CHECK(m_vk.vkCreateImageView(m_vkDevice, &imageViewCi, nullptr, &vkImageView));
105         m_vkImageViews.push_back(vkImageView);
106     }
107 }
108 
~SwapChainStateVk()109 SwapChainStateVk::~SwapChainStateVk() {
110     for (auto imageView : m_vkImageViews) {
111         m_vk.vkDestroyImageView(m_vkDevice, imageView, nullptr);
112     }
113     m_vk.vkDestroySwapchainKHR(m_vkDevice, m_vkSwapChain, nullptr);
114 }
115 
getRequiredInstanceExtensions()116 std::vector<const char *> SwapChainStateVk::getRequiredInstanceExtensions() {
117     return {
118         VK_KHR_SURFACE_EXTENSION_NAME,
119 #ifdef _WIN32
120         VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
121 #endif
122 #ifdef __APPLE__
123         VK_EXT_METAL_SURFACE_EXTENSION_NAME,
124 #endif
125 #ifdef VK_USE_PLATFORM_XCB_KHR
126         VK_KHR_XCB_SURFACE_EXTENSION_NAME,
127 #endif
128     };
129 }
130 
getRequiredDeviceExtensions()131 std::vector<const char *> SwapChainStateVk::getRequiredDeviceExtensions() {
132     return {
133         VK_KHR_SWAPCHAIN_EXTENSION_NAME,
134     };
135 }
136 
validateQueueFamilyProperties(const goldfish_vk::VulkanDispatch & vk,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,uint32_t queueFamilyIndex)137 bool SwapChainStateVk::validateQueueFamilyProperties(const goldfish_vk::VulkanDispatch &vk,
138                                                      VkPhysicalDevice physicalDevice,
139                                                      VkSurfaceKHR surface,
140                                                      uint32_t queueFamilyIndex) {
141     VkBool32 presentSupport = VK_FALSE;
142     VK_CHECK(vk.vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface,
143                                                      &presentSupport));
144     return presentSupport;
145 }
146 
createSwapChainCi(const goldfish_vk::VulkanDispatch & vk,VkSurfaceKHR surface,VkPhysicalDevice physicalDevice,uint32_t width,uint32_t height,const std::unordered_set<uint32_t> & queueFamilyIndices)147 std::optional<SwapchainCreateInfoWrapper> SwapChainStateVk::createSwapChainCi(
148     const goldfish_vk::VulkanDispatch& vk, VkSurfaceKHR surface, VkPhysicalDevice physicalDevice,
149     uint32_t width, uint32_t height, const std::unordered_set<uint32_t>& queueFamilyIndices) {
150     uint32_t formatCount = 0;
151     VK_CHECK(
152         vk.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr));
153     std::vector<VkSurfaceFormatKHR> formats(formatCount);
154     VkResult res = vk.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount,
155                                                            formats.data());
156     // b/217226027: drivers may return VK_INCOMPLETE with pSurfaceFormatCount returned by
157     // vkGetPhysicalDeviceSurfaceFormatsKHR. Retry here as a work around to the potential driver
158     // bug.
159     if (res == VK_INCOMPLETE) {
160         formatCount = (formatCount + 1) * 2;
161         INFO(
162             "VK_INCOMPLETE returned by vkGetPhysicalDeviceSurfaceFormatsKHR. A possible driver "
163             "bug. Retry with *pSurfaceFormatCount = %" PRIu32 ".",
164             formatCount);
165         formats.resize(formatCount);
166         res = vk.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount,
167                                                       formats.data());
168         formats.resize(formatCount);
169     }
170     if (res == VK_INCOMPLETE) {
171         INFO(
172             "VK_INCOMPLETE still returned by vkGetPhysicalDeviceSurfaceFormatsKHR with retry. A "
173             "possible driver bug.");
174     } else {
175         VK_CHECK(res);
176     }
177     auto iSurfaceFormat =
178         std::find_if(formats.begin(), formats.end(), [](const VkSurfaceFormatKHR &format) {
179             return format.format == k_vkFormat && format.colorSpace == k_vkColorSpace;
180         });
181     if (iSurfaceFormat == formats.end()) {
182         SWAPCHAINSTATE_VK_ERROR("Fail to create swapchain: the format(%#" PRIx64
183                                 ") with color space(%#" PRIx64 ") not supported.",
184                                 static_cast<uint64_t>(k_vkFormat),
185                                 static_cast<uint64_t>(k_vkColorSpace));
186         return std::nullopt;
187     }
188 
189     uint32_t presentModeCount = 0;
190     VK_CHECK(vk.vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface,
191                                                           &presentModeCount, nullptr));
192     std::vector<VkPresentModeKHR> presentModes_(presentModeCount);
193     VK_CHECK(vk.vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface,
194                                                           &presentModeCount, presentModes_.data()));
195     std::unordered_set<VkPresentModeKHR> presentModes(presentModes_.begin(), presentModes_.end());
196     VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
197     if (!presentModes.count(VK_PRESENT_MODE_FIFO_KHR)) {
198         SWAPCHAINSTATE_VK_ERROR("Fail to create swapchain: FIFO present mode not supported.");
199         return std::nullopt;
200     }
201     VkFormatProperties formatProperties = {};
202     vk.vkGetPhysicalDeviceFormatProperties(physicalDevice, k_vkFormat, &formatProperties);
203     // According to the spec, a presentable image is equivalent to a non-presentable image created
204     // with the VK_IMAGE_TILING_OPTIMAL tiling parameter.
205     VkFormatFeatureFlags formatFeatures = formatProperties.optimalTilingFeatures;
206     if (!(formatFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) {
207         // According to VUID-vkCmdBlitImage-dstImage-02000, the format features of dstImage must
208         // contain VK_FORMAT_FEATURE_BLIT_DST_BIT.
209         SWAPCHAINSTATE_VK_ERROR(
210             "The format %s with the optimal tiling doesn't support VK_FORMAT_FEATURE_BLIT_DST_BIT. "
211             "The supported features are %s.",
212             string_VkFormat(k_vkFormat), string_VkFormatFeatureFlags(formatFeatures).c_str());
213         return std::nullopt;
214     }
215     VkSurfaceCapabilitiesKHR surfaceCaps;
216     VK_CHECK(vk.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfaceCaps));
217     if (!(surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
218         SWAPCHAINSTATE_VK_ERROR(
219             "The supported usage flags of the presentable images is %s, and don't contain "
220             "VK_IMAGE_USAGE_TRANSFER_DST_BIT.",
221             string_VkImageUsageFlags(surfaceCaps.supportedUsageFlags).c_str());
222         return std::nullopt;
223     }
224     std::optional<VkExtent2D> maybeExtent = std::nullopt;
225     if (surfaceCaps.currentExtent.width != UINT32_MAX && surfaceCaps.currentExtent.width == width &&
226         surfaceCaps.currentExtent.height == height) {
227         maybeExtent = surfaceCaps.currentExtent;
228     } else if (width >= surfaceCaps.minImageExtent.width &&
229                width <= surfaceCaps.maxImageExtent.width &&
230                height >= surfaceCaps.minImageExtent.height &&
231                height <= surfaceCaps.maxImageExtent.height) {
232         maybeExtent = VkExtent2D({width, height});
233     }
234     if (!maybeExtent.has_value()) {
235         SWAPCHAINSTATE_VK_ERROR("Fail to create swapchain: extent(%" PRIu64 "x%" PRIu64
236                                 ") not supported.",
237                                 static_cast<uint64_t>(width), static_cast<uint64_t>(height));
238         return std::nullopt;
239     }
240     auto extent = maybeExtent.value();
241     uint32_t imageCount = surfaceCaps.minImageCount + 1;
242     if (surfaceCaps.maxImageCount != 0 && surfaceCaps.maxImageCount < imageCount) {
243         imageCount = surfaceCaps.maxImageCount;
244     }
245     SwapchainCreateInfoWrapper swapChainCi(VkSwapchainCreateInfoKHR{
246         .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
247         .pNext = nullptr,
248         .flags = VkSwapchainCreateFlagsKHR{0},
249         .surface = surface,
250         .minImageCount = imageCount,
251         .imageFormat = iSurfaceFormat->format,
252         .imageColorSpace = iSurfaceFormat->colorSpace,
253         .imageExtent = extent,
254         .imageArrayLayers = 1,
255         .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
256         .imageSharingMode = VkSharingMode{},
257         .queueFamilyIndexCount = 0,
258         .pQueueFamilyIndices = nullptr,
259         .preTransform = surfaceCaps.currentTransform,
260         .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
261         .presentMode = presentMode,
262         .clipped = VK_TRUE,
263         .oldSwapchain = VK_NULL_HANDLE});
264     if (queueFamilyIndices.empty()) {
265         SWAPCHAINSTATE_VK_ERROR("Fail to create swapchain: no Vulkan queue family specified.");
266         return std::nullopt;
267     }
268     if (queueFamilyIndices.size() == 1) {
269         swapChainCi.mCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
270         swapChainCi.setQueueFamilyIndices({});
271     } else {
272         swapChainCi.mCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
273         swapChainCi.setQueueFamilyIndices(
274             std::vector<uint32_t>(queueFamilyIndices.begin(), queueFamilyIndices.end()));
275     }
276     return swapChainCi;
277 }
278 
getFormat()279 VkFormat SwapChainStateVk::getFormat() { return k_vkFormat; }
280 
getVkImages() const281 const std::vector<VkImage> &SwapChainStateVk::getVkImages() const { return m_vkImages; }
282 
getVkImageViews() const283 const std::vector<VkImageView> &SwapChainStateVk::getVkImageViews() const { return m_vkImageViews; }
284 
getSwapChain() const285 VkSwapchainKHR SwapChainStateVk::getSwapChain() const { return m_vkSwapChain; }
286