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