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