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, ®ion, 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