1 #include "DisplayVk.h"
2 
3 #include <algorithm>
4 #include <glm/glm.hpp>
5 #include <glm/gtx/matrix_transform_2d.hpp>
6 
7 #include "host-common/GfxstreamFatalError.h"
8 #include "host-common/logging.h"
9 #include "vulkan/VkFormatUtils.h"
10 #include "vulkan/vk_enum_string_helper.h"
11 
12 namespace gfxstream {
13 namespace vk {
14 
15 using emugl::ABORT_REASON_OTHER;
16 using emugl::FatalError;
17 
18 #define DISPLAY_VK_ERROR(fmt, ...)                                                            \
19     do {                                                                                      \
20         fprintf(stderr, "%s(%s:%d): " fmt "\n", __func__, __FILE__, __LINE__, ##__VA_ARGS__); \
21         fflush(stderr);                                                                       \
22     } while (0)
23 
24 #define DISPLAY_VK_ERROR_ONCE(fmt, ...)              \
25     do {                                             \
26         static bool displayVkInternalLogged = false; \
27         if (!displayVkInternalLogged) {              \
28             DISPLAY_VK_ERROR(fmt, ##__VA_ARGS__);    \
29             displayVkInternalLogged = true;          \
30         }                                            \
31     } while (0)
32 
33 namespace {
34 
shouldRecreateSwapchain(VkResult result)35 bool shouldRecreateSwapchain(VkResult result) {
36     switch (result) {
37         case VK_SUBOPTIMAL_KHR:
38         case VK_ERROR_OUT_OF_DATE_KHR:
39         // b/217229121: drivers may return VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT in
40         // vkQueuePresentKHR even if VK_EXT_full_screen_exclusive is not enabled.
41         case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
42             return true;
43 
44         default:
45             return false;
46     }
47 }
48 
49 }  // namespace
50 
DisplayVk(const VulkanDispatch & vk,VkPhysicalDevice vkPhysicalDevice,uint32_t swapChainQueueFamilyIndex,uint32_t compositorQueueFamilyIndex,VkDevice vkDevice,VkQueue compositorVkQueue,std::shared_ptr<android::base::Lock> compositorVkQueueLock,VkQueue swapChainVkqueue,std::shared_ptr<android::base::Lock> swapChainVkQueueLock)51 DisplayVk::DisplayVk(const VulkanDispatch& vk, VkPhysicalDevice vkPhysicalDevice,
52                      uint32_t swapChainQueueFamilyIndex, uint32_t compositorQueueFamilyIndex,
53                      VkDevice vkDevice, VkQueue compositorVkQueue,
54                      std::shared_ptr<android::base::Lock> compositorVkQueueLock,
55                      VkQueue swapChainVkqueue,
56                      std::shared_ptr<android::base::Lock> swapChainVkQueueLock)
57     : m_vk(vk),
58       m_vkPhysicalDevice(vkPhysicalDevice),
59       m_swapChainQueueFamilyIndex(swapChainQueueFamilyIndex),
60       m_compositorQueueFamilyIndex(compositorQueueFamilyIndex),
61       m_vkDevice(vkDevice),
62       m_compositorVkQueue(compositorVkQueue),
63       m_compositorVkQueueLock(compositorVkQueueLock),
64       m_swapChainVkQueue(swapChainVkqueue),
65       m_swapChainVkQueueLock(swapChainVkQueueLock),
66       m_vkCommandPool(VK_NULL_HANDLE),
67       m_swapChainStateVk(nullptr) {
68     // TODO(kaiyili): validate the capabilites of the passed in Vulkan
69     // components.
70     VkCommandPoolCreateInfo commandPoolCi = {
71         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
72         .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
73         .queueFamilyIndex = m_compositorQueueFamilyIndex,
74     };
75     VK_CHECK(m_vk.vkCreateCommandPool(m_vkDevice, &commandPoolCi, nullptr, &m_vkCommandPool));
76     constexpr size_t imageBorrowResourcePoolSize = 10;
77     for (size_t i = 0; i < imageBorrowResourcePoolSize; i++) {
78         m_imageBorrowResources.emplace_back(
79             ImageBorrowResource::create(m_vk, m_vkDevice, m_vkCommandPool));
80     }
81 }
82 
~DisplayVk()83 DisplayVk::~DisplayVk() {
84     destroySwapchain();
85     m_imageBorrowResources.clear();
86     m_vk.vkDestroyCommandPool(m_vkDevice, m_vkCommandPool, nullptr);
87 }
88 
drainQueues()89 void DisplayVk::drainQueues() {
90     {
91         android::base::AutoLock lock(*m_swapChainVkQueueLock);
92         VK_CHECK(vk_util::waitForVkQueueIdleWithRetry(m_vk, m_swapChainVkQueue));
93     }
94     // We don't assume all VkCommandBuffer submitted to m_compositorVkQueueLock is always followed
95     // by another operation on the m_swapChainVkQueue. Therefore, only waiting for the
96     // m_swapChainVkQueue is not enough to guarantee all resources used are free to be destroyed.
97     {
98         android::base::AutoLock lock(*m_compositorVkQueueLock);
99         VK_CHECK(vk_util::waitForVkQueueIdleWithRetry(m_vk, m_compositorVkQueue));
100     }
101 }
102 
bindToSurfaceImpl(gfxstream::DisplaySurface * surface)103 void DisplayVk::bindToSurfaceImpl(gfxstream::DisplaySurface* surface) {
104     m_needToRecreateSwapChain = true;
105 }
106 
surfaceUpdated(gfxstream::DisplaySurface * surface)107 void DisplayVk::surfaceUpdated(gfxstream::DisplaySurface* surface) {
108     m_needToRecreateSwapChain = true;
109 }
110 
unbindFromSurfaceImpl()111 void DisplayVk::unbindFromSurfaceImpl() {
112     destroySwapchain();
113 }
114 
destroySwapchain()115 void DisplayVk::destroySwapchain() {
116     drainQueues();
117     m_freePostResources.clear();
118     m_postResourceFutures.clear();
119     m_swapChainStateVk.reset();
120     m_needToRecreateSwapChain = true;
121 }
122 
recreateSwapchain()123 bool DisplayVk::recreateSwapchain() {
124     destroySwapchain();
125 
126     const auto* surface = getBoundSurface();
127     if (!surface) {
128         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
129             << "DisplayVk can't create VkSwapchainKHR without a VkSurfaceKHR";
130     }
131     const auto* surfaceVk = static_cast<const DisplaySurfaceVk*>(surface->getImpl());
132 
133     if (!SwapChainStateVk::validateQueueFamilyProperties(m_vk, m_vkPhysicalDevice,
134                                                          surfaceVk->getSurface(),
135                                                          m_swapChainQueueFamilyIndex)) {
136         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
137             << "DisplayVk can't create VkSwapchainKHR with given VkDevice and VkSurfaceKHR.";
138     }
139     INFO("Creating swapchain with size %" PRIu32 "x%" PRIu32 ".", surface->getWidth(),
140          surface->getHeight());
141     auto swapChainCi = SwapChainStateVk::createSwapChainCi(
142         m_vk, surfaceVk->getSurface(), m_vkPhysicalDevice, surface->getWidth(),
143         surface->getHeight(), {m_swapChainQueueFamilyIndex, m_compositorQueueFamilyIndex});
144     if (!swapChainCi) {
145         return false;
146     }
147     VkFormatProperties formatProps;
148     m_vk.vkGetPhysicalDeviceFormatProperties(m_vkPhysicalDevice,
149                                              swapChainCi->mCreateInfo.imageFormat, &formatProps);
150     if (!(formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
151         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
152             << "DisplayVk: The image format chosen for present VkImage can't be used as the color "
153                "attachment, and therefore can't be used as the render target of CompositorVk.";
154     }
155     m_swapChainStateVk =
156         SwapChainStateVk::createSwapChainVk(m_vk, m_vkDevice, swapChainCi->mCreateInfo);
157     if (m_swapChainStateVk == nullptr) return false;
158     int numSwapChainImages = m_swapChainStateVk->getVkImages().size();
159 
160     m_postResourceFutures.resize(numSwapChainImages, std::nullopt);
161     for (uint32_t i = 0; i < numSwapChainImages + 1; ++i) {
162         m_freePostResources.emplace_back(PostResource::create(m_vk, m_vkDevice, m_vkCommandPool));
163     }
164 
165     m_inFlightFrameIndex = 0;
166     m_needToRecreateSwapChain = false;
167     return true;
168 }
169 
post(const BorrowedImageInfo * sourceImageInfo)170 DisplayVk::PostResult DisplayVk::post(const BorrowedImageInfo* sourceImageInfo) {
171     auto completedFuture = std::async(std::launch::deferred, [] {}).share();
172     completedFuture.wait();
173 
174     const auto* surface = getBoundSurface();
175     if (!surface) {
176         ERR("Trying to present to non-existing surface!");
177         return PostResult{
178             .success = true,
179             .postCompletedWaitable = completedFuture,
180         };
181     }
182 
183     if (m_needToRecreateSwapChain) {
184         INFO("Recreating swapchain...");
185 
186         constexpr const int kMaxRecreateSwapchainRetries = 8;
187         int retriesRemaining = kMaxRecreateSwapchainRetries;
188         while (retriesRemaining >= 0 && !recreateSwapchain()) {
189             std::this_thread::sleep_for(std::chrono::milliseconds(1));
190             --retriesRemaining;
191             INFO("Swapchain recreation failed, retrying...");
192         }
193 
194         if (retriesRemaining < 0) {
195             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
196                 << "Failed to create Swapchain."
197                 << " w:" << surface->getWidth()
198                 << " h:" << surface->getHeight();
199         }
200 
201         INFO("Recreating swapchain completed.");
202     }
203 
204     auto result = postImpl(sourceImageInfo);
205     if (!result.success) {
206         m_needToRecreateSwapChain = true;
207     }
208     return result;
209 }
210 
postImpl(const BorrowedImageInfo * sourceImageInfo)211 DisplayVk::PostResult DisplayVk::postImpl(
212     const BorrowedImageInfo* sourceImageInfo) {
213     auto completedFuture = std::async(std::launch::deferred, [] {}).share();
214     completedFuture.wait();
215 
216     // One for acquire, one for release.
217     const ImageBorrowResource* imageBorrowResources[2] = {nullptr};
218     for (size_t i = 0; i < std::size(imageBorrowResources); i++) {
219         auto freeImageBorrowResource =
220             std::find_if(m_imageBorrowResources.begin(), m_imageBorrowResources.end(),
221                          [this](const std::unique_ptr<ImageBorrowResource>& imageBorrowResource) {
222                              VkResult fenceStatus = m_vk.vkGetFenceStatus(
223                                  m_vkDevice, imageBorrowResource->m_completeFence);
224                              if (fenceStatus == VK_SUCCESS) { return true; }
225                              if (fenceStatus == VK_NOT_READY) { return false; }
226                              VK_CHECK(fenceStatus);
227                              return false;
228                          });
229         if (freeImageBorrowResource == m_imageBorrowResources.end()) {
230             freeImageBorrowResource = m_imageBorrowResources.begin();
231             VK_CHECK(m_vk.vkWaitForFences(
232                 m_vkDevice, 1, &(*freeImageBorrowResource)->m_completeFence, VK_TRUE, UINT64_MAX));
233         }
234         VK_CHECK(m_vk.vkResetFences(m_vkDevice, 1, &(*freeImageBorrowResource)->m_completeFence));
235         imageBorrowResources[i] = freeImageBorrowResource->get();
236     }
237     // We need to unconditionally acquire and release the image to satisfy the requiremment for the
238     // borrowed image.
239     const auto* sourceImageInfoVk = static_cast<const BorrowedImageInfoVk*>(sourceImageInfo);
240     struct ImageBorrower {
241         ImageBorrower(const VulkanDispatch& vk, VkQueue queue,
242                       std::shared_ptr<android::base::Lock> queueLock, uint32_t usedQueueFamilyIndex,
243                       const BorrowedImageInfoVk& image, const ImageBorrowResource& acquireResource,
244                       const ImageBorrowResource& releaseResource)
245             : m_vk(vk),
246               m_vkQueue(queue),
247               m_queueLock(queueLock),
248               m_releaseResource(releaseResource) {
249             std::vector<VkImageMemoryBarrier> acquireQueueTransferBarriers;
250             std::vector<VkImageMemoryBarrier> acquireLayoutTransitionBarriers;
251             std::vector<VkImageMemoryBarrier> releaseLayoutTransitionBarriers;
252             std::vector<VkImageMemoryBarrier> releaseQueueTransferBarriers;
253             addNeededBarriersToUseBorrowedImage(
254                 image, usedQueueFamilyIndex,
255                 /*usedInitialImageLayout=*/VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
256                 /*usedFinalImageLayout=*/VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
257                 VK_ACCESS_TRANSFER_READ_BIT, &acquireQueueTransferBarriers,
258                 &acquireLayoutTransitionBarriers, &releaseLayoutTransitionBarriers,
259                 &releaseQueueTransferBarriers);
260 
261             // Record the acquire commands.
262             const VkCommandBufferBeginInfo acquireBeginInfo = {
263                 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
264                 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
265             };
266             VK_CHECK(
267                 m_vk.vkBeginCommandBuffer(acquireResource.m_vkCommandBuffer, &acquireBeginInfo));
268             if (!acquireQueueTransferBarriers.empty()) {
269                 m_vk.vkCmdPipelineBarrier(
270                     acquireResource.m_vkCommandBuffer,
271                     VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
272                     VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
273                     0, 0, nullptr, 0, nullptr,
274                     static_cast<uint32_t>(acquireQueueTransferBarriers.size()),
275                     acquireQueueTransferBarriers.data());
276             }
277             if (!acquireLayoutTransitionBarriers.empty()) {
278                 m_vk.vkCmdPipelineBarrier(
279                     acquireResource.m_vkCommandBuffer,
280                     VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
281                     VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr,
282                     static_cast<uint32_t>(acquireLayoutTransitionBarriers.size()),
283                     acquireLayoutTransitionBarriers.data());
284             }
285             VK_CHECK(m_vk.vkEndCommandBuffer(acquireResource.m_vkCommandBuffer));
286 
287             // Record the release commands.
288             const VkCommandBufferBeginInfo releaseBeginInfo = {
289                 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
290                 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
291             };
292             VK_CHECK(
293                 m_vk.vkBeginCommandBuffer(releaseResource.m_vkCommandBuffer, &releaseBeginInfo));
294             if (!releaseLayoutTransitionBarriers.empty()) {
295                 m_vk.vkCmdPipelineBarrier(
296                     releaseResource.m_vkCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
297                     VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr,
298                     static_cast<uint32_t>(releaseLayoutTransitionBarriers.size()),
299                     releaseLayoutTransitionBarriers.data());
300             }
301             if (!releaseQueueTransferBarriers.empty()) {
302                 m_vk.vkCmdPipelineBarrier(
303                     releaseResource.m_vkCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
304                     VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr,
305                     static_cast<uint32_t>(releaseQueueTransferBarriers.size()),
306                     releaseQueueTransferBarriers.data());
307             }
308             VK_CHECK(m_vk.vkEndCommandBuffer(releaseResource.m_vkCommandBuffer));
309 
310             VkSubmitInfo submitInfo = {
311                 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
312                 .waitSemaphoreCount = 0,
313                 .pWaitSemaphores = nullptr,
314                 .pWaitDstStageMask = nullptr,
315                 .commandBufferCount = 1,
316                 .pCommandBuffers = &acquireResource.m_vkCommandBuffer,
317                 .signalSemaphoreCount = 0,
318                 .pSignalSemaphores = nullptr,
319             };
320             // Submit the acquire commands.
321             {
322                 android::base::AutoLock lock(*m_queueLock);
323                 VK_CHECK(
324                     m_vk.vkQueueSubmit(m_vkQueue, 1, &submitInfo, acquireResource.m_completeFence));
325             }
326         }
327 
328         const VulkanDispatch& m_vk;
329         const VkQueue m_vkQueue;
330         std::shared_ptr<android::base::Lock> m_queueLock;
331         const ImageBorrowResource& m_releaseResource;
332         ~ImageBorrower() {
333             VkSubmitInfo submitInfo = {
334                 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
335                 .waitSemaphoreCount = 0,
336                 .pWaitSemaphores = nullptr,
337                 .pWaitDstStageMask = nullptr,
338                 .commandBufferCount = 1,
339                 .pCommandBuffers = &m_releaseResource.m_vkCommandBuffer,
340                 .signalSemaphoreCount = 0,
341                 .pSignalSemaphores = nullptr,
342             };
343             // Submit the release commands.
344             {
345                 android::base::AutoLock lock(*m_queueLock);
346                 VK_CHECK(m_vk.vkQueueSubmit(m_vkQueue, 1, &submitInfo,
347                                             m_releaseResource.m_completeFence));
348             }
349         }
350     } imageBorrower(m_vk, m_compositorVkQueue, m_compositorVkQueueLock,
351                     m_compositorQueueFamilyIndex, *sourceImageInfoVk, *imageBorrowResources[0],
352                     *imageBorrowResources[1]);
353 
354     const auto* surface = getBoundSurface();
355     if (!m_swapChainStateVk || !surface) {
356         DISPLAY_VK_ERROR("Haven't bound to a surface, can't post ColorBuffer.");
357         return PostResult{true, std::move(completedFuture)};
358     }
359 
360     if (!canPost(sourceImageInfoVk->imageCreateInfo)) {
361         DISPLAY_VK_ERROR("Can't post ColorBuffer.");
362         return PostResult{true, std::move(completedFuture)};
363     }
364 
365     for (auto& postResourceFutureOpt : m_postResourceFutures) {
366         if (!postResourceFutureOpt.has_value()) {
367             continue;
368         }
369         auto postResourceFuture = postResourceFutureOpt.value();
370         if (!postResourceFuture.valid()) {
371             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
372                 << "Invalid postResourceFuture in m_postResourceFutures.";
373         }
374         std::future_status status = postResourceFuture.wait_for(std::chrono::seconds(0));
375         if (status == std::future_status::ready) {
376             m_freePostResources.emplace_back(postResourceFuture.get());
377             postResourceFutureOpt = std::nullopt;
378         }
379     }
380     if (m_freePostResources.empty()) {
381         for (auto& postResourceFutureOpt : m_postResourceFutures) {
382             if (!postResourceFutureOpt.has_value()) {
383                 continue;
384             }
385             m_freePostResources.emplace_back(postResourceFutureOpt.value().get());
386             postResourceFutureOpt = std::nullopt;
387             break;
388         }
389     }
390     std::shared_ptr<PostResource> postResource = m_freePostResources.front();
391     m_freePostResources.pop_front();
392 
393     VkSemaphore imageReadySem = postResource->m_swapchainImageAcquireSemaphore;
394 
395     uint32_t imageIndex;
396     VkResult acquireRes =
397         m_vk.vkAcquireNextImageKHR(m_vkDevice, m_swapChainStateVk->getSwapChain(), UINT64_MAX,
398                                    imageReadySem, VK_NULL_HANDLE, &imageIndex);
399     if (shouldRecreateSwapchain(acquireRes)) {
400         return PostResult{false, std::shared_future<void>()};
401     }
402     VK_CHECK(acquireRes);
403 
404     if (m_postResourceFutures[imageIndex].has_value()) {
405         m_freePostResources.emplace_back(m_postResourceFutures[imageIndex].value().get());
406         m_postResourceFutures[imageIndex] = std::nullopt;
407     }
408 
409     VkCommandBuffer cmdBuff = postResource->m_vkCommandBuffer;
410     VK_CHECK(m_vk.vkResetCommandBuffer(cmdBuff, 0));
411 
412     const VkCommandBufferBeginInfo beginInfo = {
413         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
414         .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
415     };
416     VK_CHECK(m_vk.vkBeginCommandBuffer(cmdBuff, &beginInfo));
417 
418     VkImageMemoryBarrier acquireSwapchainImageBarrier = {
419         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
420         .pNext = nullptr,
421         .srcAccessMask = VK_PIPELINE_STAGE_TRANSFER_BIT,
422         .dstAccessMask = VK_PIPELINE_STAGE_TRANSFER_BIT,
423         .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
424         .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
425         .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
426         .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
427         .image = m_swapChainStateVk->getVkImages()[imageIndex],
428         .subresourceRange =
429             {
430                 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
431                 .baseMipLevel = 0,
432                 .levelCount = 1,
433                 .baseArrayLayer = 0,
434                 .layerCount = 1,
435             },
436     };
437     m_vk.vkCmdPipelineBarrier(cmdBuff, VK_PIPELINE_STAGE_TRANSFER_BIT,
438                               VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
439                               &acquireSwapchainImageBarrier);
440 
441     // Note: The extent used during swapchain creation must be used here and not the
442     // current surface's extent as the swapchain may not have been updated after the
443     // surface resized. The blit must not try to write outside of the extent of the
444     // existing swapchain images.
445     const VkExtent2D swapchainImageExtent = m_swapChainStateVk->getImageExtent();
446     const VkImageBlit region = {
447         .srcSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
448                            .mipLevel = 0,
449                            .baseArrayLayer = 0,
450                            .layerCount = 1},
451         .srcOffsets = {{0, 0, 0},
452                        {static_cast<int32_t>(sourceImageInfoVk->imageCreateInfo.extent.width),
453                         static_cast<int32_t>(sourceImageInfoVk->imageCreateInfo.extent.height), 1}},
454         .dstSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
455                            .mipLevel = 0,
456                            .baseArrayLayer = 0,
457                            .layerCount = 1},
458         .dstOffsets = {{0, 0, 0},
459                        {static_cast<int32_t>(swapchainImageExtent.width),
460                         static_cast<int32_t>(swapchainImageExtent.height), 1}},
461     };
462     VkFormat displayBufferFormat = sourceImageInfoVk->imageCreateInfo.format;
463     VkImageTiling displayBufferTiling = sourceImageInfoVk->imageCreateInfo.tiling;
464     VkFilter filter = VK_FILTER_NEAREST;
465     VkFormatFeatureFlags displayBufferFormatFeatures =
466         getFormatFeatures(displayBufferFormat, displayBufferTiling);
467     if (formatIsDepthOrStencil(displayBufferFormat)) {
468         DISPLAY_VK_ERROR_ONCE(
469             "The format of the display buffer, %s, is a depth/stencil format, we can only use the "
470             "VK_FILTER_NEAREST filter according to VUID-vkCmdBlitImage-srcImage-00232.",
471             string_VkFormat(displayBufferFormat));
472         filter = VK_FILTER_NEAREST;
473     } else if (!(displayBufferFormatFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
474         DISPLAY_VK_ERROR_ONCE(
475             "The format of the display buffer, %s, with the tiling, %s, doesn't support "
476             "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT, so we can only use the "
477             "VK_FILTER_NEAREST filter according VUID-vkCmdBlitImage-filter-02001. The supported "
478             "features are %s.",
479             string_VkFormat(displayBufferFormat), string_VkImageTiling(displayBufferTiling),
480             string_VkFormatFeatureFlags(displayBufferFormatFeatures).c_str());
481         filter = VK_FILTER_NEAREST;
482     } else {
483         filter = VK_FILTER_LINEAR;
484     }
485     m_vk.vkCmdBlitImage(cmdBuff, sourceImageInfoVk->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
486                         m_swapChainStateVk->getVkImages()[imageIndex],
487                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, filter);
488 
489     VkImageMemoryBarrier releaseSwapchainImageBarrier = {
490         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
491         .srcAccessMask = VK_PIPELINE_STAGE_TRANSFER_BIT,
492         .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
493         .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
494         .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
495         .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
496         .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
497         .image = m_swapChainStateVk->getVkImages()[imageIndex],
498         .subresourceRange =
499             {
500                 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
501                 .baseMipLevel = 0,
502                 .levelCount = 1,
503                 .baseArrayLayer = 0,
504                 .layerCount = 1,
505             },
506     };
507     m_vk.vkCmdPipelineBarrier(cmdBuff, VK_PIPELINE_STAGE_TRANSFER_BIT,
508                               VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
509                               &releaseSwapchainImageBarrier);
510 
511     VK_CHECK(m_vk.vkEndCommandBuffer(cmdBuff));
512 
513     VkFence postCompleteFence = postResource->m_swapchainImageReleaseFence;
514     VK_CHECK(m_vk.vkResetFences(m_vkDevice, 1, &postCompleteFence));
515     VkSemaphore postCompleteSemaphore = postResource->m_swapchainImageReleaseSemaphore;
516     VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_TRANSFER_BIT};
517     VkSubmitInfo submitInfo = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
518                                .waitSemaphoreCount = 1,
519                                .pWaitSemaphores = &imageReadySem,
520                                .pWaitDstStageMask = waitStages,
521                                .commandBufferCount = 1,
522                                .pCommandBuffers = &cmdBuff,
523                                .signalSemaphoreCount = 1,
524                                .pSignalSemaphores = &postCompleteSemaphore};
525     {
526         android::base::AutoLock lock(*m_compositorVkQueueLock);
527         VK_CHECK(m_vk.vkQueueSubmit(m_compositorVkQueue, 1, &submitInfo, postCompleteFence));
528     }
529     std::shared_future<std::shared_ptr<PostResource>> postResourceFuture =
530         std::async(std::launch::deferred, [postCompleteFence, postResource, this]() mutable {
531             VkResult res = m_vk.vkWaitForFences(m_vkDevice, 1, &postCompleteFence, VK_TRUE,
532                                                 kVkWaitForFencesTimeoutNsecs);
533             if (res == VK_SUCCESS) {
534                 return postResource;
535             }
536             if (res == VK_TIMEOUT) {
537                 // Retry. If device lost, hopefully this returns immediately.
538                 res = m_vk.vkWaitForFences(m_vkDevice, 1, &postCompleteFence, VK_TRUE,
539                                            kVkWaitForFencesTimeoutNsecs);
540             }
541             VK_CHECK(res);
542             return postResource;
543         }).share();
544     m_postResourceFutures[imageIndex] = postResourceFuture;
545 
546     auto swapChain = m_swapChainStateVk->getSwapChain();
547     VkPresentInfoKHR presentInfo = {.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
548                                     .waitSemaphoreCount = 1,
549                                     .pWaitSemaphores = &postCompleteSemaphore,
550                                     .swapchainCount = 1,
551                                     .pSwapchains = &swapChain,
552                                     .pImageIndices = &imageIndex};
553     VkResult presentRes;
554     {
555         android::base::AutoLock lock(*m_swapChainVkQueueLock);
556         presentRes = m_vk.vkQueuePresentKHR(m_swapChainVkQueue, &presentInfo);
557     }
558     if (shouldRecreateSwapchain(presentRes)) {
559         postResourceFuture.wait();
560         return PostResult{false, std::shared_future<void>()};
561     }
562     VK_CHECK(presentRes);
563     return PostResult{true, std::async(std::launch::deferred, [postResourceFuture] {
564                                 // We can't directly wait for the VkFence here, because we
565                                 // share the VkFences on different frames, but we don't share
566                                 // the future on different frames. If we directly wait for the
567                                 // VkFence here, we may wait for a different frame if a new
568                                 // frame starts to be drawn before this future is waited.
569                                 postResourceFuture.wait();
570                             }).share()};
571 }
572 
getFormatFeatures(VkFormat format,VkImageTiling tiling)573 VkFormatFeatureFlags DisplayVk::getFormatFeatures(VkFormat format, VkImageTiling tiling) {
574     auto i = m_vkFormatProperties.find(format);
575     if (i == m_vkFormatProperties.end()) {
576         VkFormatProperties formatProperties;
577         m_vk.vkGetPhysicalDeviceFormatProperties(m_vkPhysicalDevice, format, &formatProperties);
578         i = m_vkFormatProperties.emplace(format, formatProperties).first;
579     }
580     const VkFormatProperties& formatProperties = i->second;
581     VkFormatFeatureFlags formatFeatures = 0;
582     if (tiling == VK_IMAGE_TILING_LINEAR) {
583         formatFeatures = formatProperties.linearTilingFeatures;
584     } else if (tiling == VK_IMAGE_TILING_OPTIMAL) {
585         formatFeatures = formatProperties.optimalTilingFeatures;
586     } else {
587         DISPLAY_VK_ERROR("Unknown tiling %#" PRIx64 ".", static_cast<uint64_t>(tiling));
588     }
589     return formatFeatures;
590 }
591 
canPost(const VkImageCreateInfo & postImageCi)592 bool DisplayVk::canPost(const VkImageCreateInfo& postImageCi) {
593     // According to VUID-vkCmdBlitImage-srcImage-01999, the format features of srcImage must contain
594     // VK_FORMAT_FEATURE_BLIT_SRC_BIT.
595     VkFormatFeatureFlags formatFeatures = getFormatFeatures(postImageCi.format, postImageCi.tiling);
596     if (!(formatFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) {
597         DISPLAY_VK_ERROR(
598             "VK_FORMAT_FEATURE_BLIT_SRC_BLIT is not supported for VkImage with format %s, tilling "
599             "%s. Supported features are %s.",
600             string_VkFormat(postImageCi.format), string_VkImageTiling(postImageCi.tiling),
601             string_VkFormatFeatureFlags(formatFeatures).c_str());
602         return false;
603     }
604 
605     // According to VUID-vkCmdBlitImage-srcImage-06421, srcImage must not use a format that requires
606     // a sampler Y’CBCR conversion.
607     if (formatRequiresSamplerYcbcrConversion(postImageCi.format)) {
608         DISPLAY_VK_ERROR("Format %s requires a sampler Y'CbCr conversion. Can't be used to post.",
609                          string_VkFormat(postImageCi.format));
610         return false;
611     }
612 
613     if (!(postImageCi.usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
614         // According to VUID-vkCmdBlitImage-srcImage-00219, srcImage must have been created with
615         // VK_IMAGE_USAGE_TRANSFER_SRC_BIT usage flag.
616         DISPLAY_VK_ERROR(
617             "The VkImage is not created with the VK_IMAGE_USAGE_TRANSFER_SRC_BIT usage flag. The "
618             "usage flags are %s.",
619             string_VkImageUsageFlags(postImageCi.usage).c_str());
620         return false;
621     }
622 
623     VkFormat swapChainFormat = m_swapChainStateVk->getFormat();
624     if (formatIsSInt(postImageCi.format) || formatIsSInt(swapChainFormat)) {
625         // According to VUID-vkCmdBlitImage-srcImage-00229, if either of srcImage or dstImage was
626         // created with a signed integer VkFormat, the other must also have been created with a
627         // signed integer VkFormat.
628         if (!(formatIsSInt(postImageCi.format) && formatIsSInt(m_swapChainStateVk->getFormat()))) {
629             DISPLAY_VK_ERROR(
630                 "The format(%s) doesn't match with the format of the presentable image(%s): either "
631                 "of the formats is a signed integer VkFormat, but the other is not.",
632                 string_VkFormat(postImageCi.format), string_VkFormat(swapChainFormat));
633             return false;
634         }
635     }
636 
637     if (formatIsUInt(postImageCi.format) || formatIsUInt(swapChainFormat)) {
638         // According to VUID-vkCmdBlitImage-srcImage-00230, if either of srcImage or dstImage was
639         // created with an unsigned integer VkFormat, the other must also have been created with an
640         // unsigned integer VkFormat.
641         if (!(formatIsUInt(postImageCi.format) && formatIsUInt(swapChainFormat))) {
642             DISPLAY_VK_ERROR(
643                 "The format(%s) doesn't match with the format of the presentable image(%s): either "
644                 "of the formats is an unsigned integer VkFormat, but the other is not.",
645                 string_VkFormat(postImageCi.format), string_VkFormat(swapChainFormat));
646             return false;
647         }
648     }
649 
650     if (formatIsDepthOrStencil(postImageCi.format) || formatIsDepthOrStencil(swapChainFormat)) {
651         // According to VUID-vkCmdBlitImage-srcImage-00231, if either of srcImage or dstImage was
652         // created with a depth/stencil format, the other must have exactly the same format.
653         if (postImageCi.format != swapChainFormat) {
654             DISPLAY_VK_ERROR(
655                 "The format(%s) doesn't match with the format of the presentable image(%s): either "
656                 "of the formats is a depth/stencil VkFormat, but the other is not the same format.",
657                 string_VkFormat(postImageCi.format), string_VkFormat(swapChainFormat));
658             return false;
659         }
660     }
661 
662     if (postImageCi.samples != VK_SAMPLE_COUNT_1_BIT) {
663         // According to VUID-vkCmdBlitImage-srcImage-00233, srcImage must have been created with a
664         // samples value of VK_SAMPLE_COUNT_1_BIT.
665         DISPLAY_VK_ERROR(
666             "The VkImage is not created with the VK_SAMPLE_COUNT_1_BIT samples value. The samples "
667             "value is %s.",
668             string_VkSampleCountFlagBits(postImageCi.samples));
669         return false;
670     }
671     if (postImageCi.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
672         // According to VUID-vkCmdBlitImage-dstImage-02545, dstImage and srcImage must not have been
673         // created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT.
674         DISPLAY_VK_ERROR(
675             "The VkImage can't be created with flags containing "
676             "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT. The flags are %s.",
677             string_VkImageCreateFlags(postImageCi.flags).c_str());
678         return false;
679     }
680     return true;
681 }
682 
create(const VulkanDispatch & vk,VkDevice vkDevice,VkCommandPool vkCommandPool)683 std::shared_ptr<DisplayVk::PostResource> DisplayVk::PostResource::create(
684     const VulkanDispatch& vk, VkDevice vkDevice, VkCommandPool vkCommandPool) {
685     VkFenceCreateInfo fenceCi = {
686         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
687     };
688     VkFence fence;
689     VK_CHECK(vk.vkCreateFence(vkDevice, &fenceCi, nullptr, &fence));
690     VkSemaphore semaphores[2];
691     for (uint32_t i = 0; i < std::size(semaphores); i++) {
692         VkSemaphoreCreateInfo semaphoreCi = {
693             .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
694         };
695         VK_CHECK(vk.vkCreateSemaphore(vkDevice, &semaphoreCi, nullptr, &semaphores[i]));
696     }
697     VkCommandBuffer commandBuffer;
698     VkCommandBufferAllocateInfo commandBufferAllocInfo = {
699         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
700         .commandPool = vkCommandPool,
701         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
702         .commandBufferCount = 1,
703     };
704     VK_CHECK(vk.vkAllocateCommandBuffers(vkDevice, &commandBufferAllocInfo, &commandBuffer));
705     return std::shared_ptr<PostResource>(new PostResource(
706         vk, vkDevice, vkCommandPool, fence, semaphores[0], semaphores[1], commandBuffer));
707 }
708 
~PostResource()709 DisplayVk::PostResource::~PostResource() {
710     m_vk.vkFreeCommandBuffers(m_vkDevice, m_vkCommandPool, 1, &m_vkCommandBuffer);
711     m_vk.vkDestroyFence(m_vkDevice, m_swapchainImageReleaseFence, nullptr);
712     m_vk.vkDestroySemaphore(m_vkDevice, m_swapchainImageAcquireSemaphore, nullptr);
713     m_vk.vkDestroySemaphore(m_vkDevice, m_swapchainImageReleaseSemaphore, nullptr);
714 }
715 
PostResource(const VulkanDispatch & vk,VkDevice vkDevice,VkCommandPool vkCommandPool,VkFence swapchainImageReleaseFence,VkSemaphore swapchainImageAcquireSemaphore,VkSemaphore swapchainImageReleaseSemaphore,VkCommandBuffer vkCommandBuffer)716 DisplayVk::PostResource::PostResource(const VulkanDispatch& vk, VkDevice vkDevice,
717                                       VkCommandPool vkCommandPool,
718                                       VkFence swapchainImageReleaseFence,
719                                       VkSemaphore swapchainImageAcquireSemaphore,
720                                       VkSemaphore swapchainImageReleaseSemaphore,
721                                       VkCommandBuffer vkCommandBuffer)
722     : m_swapchainImageReleaseFence(swapchainImageReleaseFence),
723       m_swapchainImageAcquireSemaphore(swapchainImageAcquireSemaphore),
724       m_swapchainImageReleaseSemaphore(swapchainImageReleaseSemaphore),
725       m_vkCommandBuffer(vkCommandBuffer),
726       m_vk(vk),
727       m_vkDevice(vkDevice),
728       m_vkCommandPool(vkCommandPool) {}
729 
create(const VulkanDispatch & vk,VkDevice device,VkCommandPool commandPool)730 std::unique_ptr<DisplayVk::ImageBorrowResource> DisplayVk::ImageBorrowResource::create(
731     const VulkanDispatch& vk, VkDevice device, VkCommandPool commandPool) {
732     const VkCommandBufferAllocateInfo allocInfo = {
733         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
734         .pNext = nullptr,
735         .commandPool = commandPool,
736         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
737         .commandBufferCount = 1,
738     };
739     VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
740     VK_CHECK(vk.vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer));
741     const VkFenceCreateInfo fenceCi = {
742         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
743         .pNext = nullptr,
744         .flags = VK_FENCE_CREATE_SIGNALED_BIT,
745     };
746     VkFence fence = VK_NULL_HANDLE;
747     VK_CHECK(vk.vkCreateFence(device, &fenceCi, nullptr, &fence));
748     return std::unique_ptr<ImageBorrowResource>(
749         new ImageBorrowResource(vk, device, commandPool, fence, commandBuffer));
750 }
751 
~ImageBorrowResource()752 DisplayVk::ImageBorrowResource::~ImageBorrowResource() {
753     m_vk.vkFreeCommandBuffers(m_vkDevice, m_vkCommandPool, 1, &m_vkCommandBuffer);
754 }
755 
ImageBorrowResource(const VulkanDispatch & vk,VkDevice device,VkCommandPool commandPool,VkFence fence,VkCommandBuffer commandBuffer)756 DisplayVk::ImageBorrowResource::ImageBorrowResource(const VulkanDispatch& vk, VkDevice device,
757                                                     VkCommandPool commandPool, VkFence fence,
758                                                     VkCommandBuffer commandBuffer)
759     : m_completeFence(fence),
760       m_vkCommandBuffer(commandBuffer),
761       m_vk(vk),
762       m_vkDevice(device),
763       m_vkCommandPool(commandPool) {}
764 
765 }  // namespace vk
766 }  // namespace gfxstream
767