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