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