• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "DisplayVk.h"
2 
3 #include <algorithm>
4 #include <chrono>
5 #include <glm/glm.hpp>
6 #include <glm/gtx/matrix_transform_2d.hpp>
7 #include <thread>
8 
9 #include "host-common/GfxstreamFatalError.h"
10 #include "host-common/logging.h"
11 #include "vulkan/VkCommonOperations.h"
12 #include "vulkan/VkFormatUtils.h"
13 #include "vulkan/vk_enum_string_helper.h"
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 
waitForVkQueueIdleWithRetry(const goldfish_vk::VulkanDispatch & vk,VkQueue queue)49 VkResult waitForVkQueueIdleWithRetry(const goldfish_vk::VulkanDispatch& vk, VkQueue queue) {
50     using namespace std::chrono_literals;
51     constexpr uint32_t retryLimit = 5;
52     constexpr std::chrono::duration waitInterval = 4ms;
53     VkResult res = vk.vkQueueWaitIdle(queue);
54     for (uint32_t retryTimes = 1; retryTimes < retryLimit && res == VK_TIMEOUT; retryTimes++) {
55         INFO("VK_TIMEOUT returned from vkQueueWaitIdle with %" PRIu32 " attempt. Wait for %" PRIu32
56              "ms before another attempt.",
57              retryTimes,
58              static_cast<uint32_t>(
59                  std::chrono::duration_cast<std::chrono::milliseconds>(waitInterval).count()));
60         std::this_thread::sleep_for(waitInterval);
61         res = vk.vkQueueWaitIdle(queue);
62     }
63     return res;
64 }
65 
66 }  // namespace
67 
DisplayVk(const goldfish_vk::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)68 DisplayVk::DisplayVk(const goldfish_vk::VulkanDispatch& vk, VkPhysicalDevice vkPhysicalDevice,
69                      uint32_t swapChainQueueFamilyIndex, uint32_t compositorQueueFamilyIndex,
70                      VkDevice vkDevice, VkQueue compositorVkQueue,
71                      std::shared_ptr<android::base::Lock> compositorVkQueueLock,
72                      VkQueue swapChainVkqueue,
73                      std::shared_ptr<android::base::Lock> swapChainVkQueueLock)
74     : m_vk(vk),
75       m_vkPhysicalDevice(vkPhysicalDevice),
76       m_swapChainQueueFamilyIndex(swapChainQueueFamilyIndex),
77       m_compositorQueueFamilyIndex(compositorQueueFamilyIndex),
78       m_vkDevice(vkDevice),
79       m_compositorVkQueue(compositorVkQueue),
80       m_compositorVkQueueLock(compositorVkQueueLock),
81       m_swapChainVkQueue(swapChainVkqueue),
82       m_swapChainVkQueueLock(swapChainVkQueueLock),
83       m_vkCommandPool(VK_NULL_HANDLE),
84       m_swapChainStateVk(nullptr),
85       m_compositorVk(nullptr),
86       m_surfaceState(nullptr) {
87     // TODO(kaiyili): validate the capabilites of the passed in Vulkan
88     // components.
89     VkCommandPoolCreateInfo commandPoolCi = {
90         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
91         .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
92         .queueFamilyIndex = m_compositorQueueFamilyIndex,
93     };
94     VK_CHECK(m_vk.vkCreateCommandPool(m_vkDevice, &commandPoolCi, nullptr, &m_vkCommandPool));
95 
96     VkSamplerCreateInfo samplerCi = {.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
97                                      .magFilter = VK_FILTER_LINEAR,
98                                      .minFilter = VK_FILTER_LINEAR,
99                                      .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
100                                      .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
101                                      .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
102                                      .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
103                                      .mipLodBias = 0.0f,
104                                      .anisotropyEnable = VK_FALSE,
105                                      .maxAnisotropy = 1.0f,
106                                      .compareEnable = VK_FALSE,
107                                      .compareOp = VK_COMPARE_OP_ALWAYS,
108                                      .minLod = 0.0f,
109                                      .maxLod = 0.0f,
110                                      .borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,
111                                      .unnormalizedCoordinates = VK_FALSE};
112     VK_CHECK(m_vk.vkCreateSampler(m_vkDevice, &samplerCi, nullptr, &m_compositionVkSampler));
113 }
114 
~DisplayVk()115 DisplayVk::~DisplayVk() {
116     {
117         android::base::AutoLock lock(*m_swapChainVkQueueLock);
118         VK_CHECK(waitForVkQueueIdleWithRetry(m_vk, m_swapChainVkQueue));
119     }
120     {
121         android::base::AutoLock lock(*m_compositorVkQueueLock);
122         VK_CHECK(waitForVkQueueIdleWithRetry(m_vk, m_compositorVkQueue));
123     }
124     m_postResourceFuture = std::nullopt;
125     m_composeResourceFuture = std::nullopt;
126     m_compositorVkRenderTargets.clear();
127     m_vk.vkDestroySampler(m_vkDevice, m_compositionVkSampler, nullptr);
128     m_surfaceState.reset();
129     m_compositorVk.reset();
130     m_swapChainStateVk.reset();
131     m_vk.vkDestroyCommandPool(m_vkDevice, m_vkCommandPool, nullptr);
132 }
133 
bindToSurface(VkSurfaceKHR surface,uint32_t width,uint32_t height)134 void DisplayVk::bindToSurface(VkSurfaceKHR surface, uint32_t width, uint32_t height) {
135     {
136         android::base::AutoLock lock(*m_compositorVkQueueLock);
137         VK_CHECK(waitForVkQueueIdleWithRetry(m_vk, m_compositorVkQueue));
138     }
139     {
140         android::base::AutoLock lock(*m_swapChainVkQueueLock);
141         VK_CHECK(waitForVkQueueIdleWithRetry(m_vk, m_swapChainVkQueue));
142     }
143     m_postResourceFuture = std::nullopt;
144     m_composeResourceFuture = std::nullopt;
145     m_compositorVkRenderTargets = std::deque<std::shared_ptr<CompositorVkRenderTarget>>(
146         k_compositorVkRenderTargetCacheSize, nullptr);
147     m_compositorVk.reset();
148     m_swapChainStateVk.reset();
149 
150     if (!SwapChainStateVk::validateQueueFamilyProperties(m_vk, m_vkPhysicalDevice, surface,
151                                                          m_swapChainQueueFamilyIndex)) {
152         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
153             << "DisplayVk can't create VkSwapchainKHR with given VkDevice and VkSurfaceKHR.";
154     }
155     auto swapChainCi = SwapChainStateVk::createSwapChainCi(
156         m_vk, surface, m_vkPhysicalDevice, width, height,
157         {m_swapChainQueueFamilyIndex, m_compositorQueueFamilyIndex});
158     if (!swapChainCi) {
159         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
160             << "Failed to create VkSwapchainCreateInfoKHR.";
161     }
162     VkFormatProperties formatProps;
163     m_vk.vkGetPhysicalDeviceFormatProperties(m_vkPhysicalDevice,
164                                              swapChainCi->mCreateInfo.imageFormat, &formatProps);
165     if (!(formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
166         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
167             << "DisplayVk: The image format chosen for present VkImage can't be used as the color "
168                "attachment, and therefore can't be used as the render target of CompositorVk.";
169     }
170     m_swapChainStateVk =
171         std::make_unique<SwapChainStateVk>(m_vk, m_vkDevice, swapChainCi->mCreateInfo);
172     m_compositorVk = CompositorVk::create(
173         m_vk, m_vkDevice, m_vkPhysicalDevice, m_compositorVkQueue, m_compositorVkQueueLock,
174         k_compositorVkRenderTargetFormat, VK_IMAGE_LAYOUT_UNDEFINED,
175         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_swapChainStateVk->getVkImageViews().size(),
176         m_vkCommandPool, m_compositionVkSampler);
177 
178     int numSwapChainImages = m_swapChainStateVk->getVkImages().size();
179 
180     m_postResourceFuture = std::async(std::launch::deferred, [this] {
181                                return PostResource::create(m_vk, m_vkDevice, m_vkCommandPool);
182                            }).share();
183     m_postResourceFuture.value().wait();
184 
185     m_inFlightFrameIndex = 0;
186 
187     m_composeResourceFuture = std::async(std::launch::deferred, [this] {
188         return ComposeResource::create(m_vk, m_vkDevice, m_vkCommandPool);
189     });
190     m_composeResourceFuture.value().wait();
191     auto surfaceState = std::make_unique<SurfaceState>();
192     surfaceState->m_height = height;
193     surfaceState->m_width = width;
194     m_surfaceState = std::move(surfaceState);
195 }
196 
createDisplayBuffer(VkImage image,const VkImageCreateInfo & vkImageCreateInfo)197 std::shared_ptr<DisplayVk::DisplayBufferInfo> DisplayVk::createDisplayBuffer(
198     VkImage image, const VkImageCreateInfo& vkImageCreateInfo) {
199     return std::shared_ptr<DisplayBufferInfo>(
200         new DisplayBufferInfo(m_vk, m_vkDevice, vkImageCreateInfo, image));
201 }
202 
post(std::shared_ptr<DisplayBufferInfo> displayBufferPtr)203 std::tuple<bool, std::shared_future<void>> DisplayVk::post(
204     std::shared_ptr<DisplayBufferInfo> displayBufferPtr) {
205     auto completedFuture = std::async(std::launch::deferred, [] {}).share();
206     completedFuture.wait();
207     if (!displayBufferPtr) {
208         fprintf(stderr, "%s: warning: null ptr passed to post buffer\n", __func__);
209         return std::make_tuple(true, std::move(completedFuture));
210     }
211     if (!m_swapChainStateVk || !m_surfaceState) {
212         DISPLAY_VK_ERROR("Haven't bound to a surface, can't post ColorBuffer.");
213         return std::make_tuple(true, std::move(completedFuture));
214     }
215     if (!canPost(displayBufferPtr->m_vkImageCreateInfo)) {
216         DISPLAY_VK_ERROR("Can't post ColorBuffer.");
217         return std::make_tuple(true, std::move(completedFuture));
218     }
219 
220     std::shared_ptr<PostResource> postResource = m_postResourceFuture.value().get();
221     VkSemaphore imageReadySem = postResource->m_swapchainImageAcquireSemaphore;
222 
223     uint32_t imageIndex;
224     VkResult acquireRes =
225         m_vk.vkAcquireNextImageKHR(m_vkDevice, m_swapChainStateVk->getSwapChain(), UINT64_MAX,
226                                    imageReadySem, VK_NULL_HANDLE, &imageIndex);
227     if (shouldRecreateSwapchain(acquireRes)) {
228         return std::make_tuple(false, std::shared_future<void>());
229     }
230     VK_CHECK(acquireRes);
231 
232     VkCommandBuffer cmdBuff = postResource->m_vkCommandBuffer;
233     VK_CHECK(m_vk.vkResetCommandBuffer(cmdBuff, 0));
234     VkCommandBufferBeginInfo beginInfo = {
235         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
236         .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
237     };
238     VK_CHECK(m_vk.vkBeginCommandBuffer(cmdBuff, &beginInfo));
239     VkImageMemoryBarrier presentToXferDstBarrier = {
240         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
241         .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
242         .dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
243         .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
244         .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
245         .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
246         .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
247         .image = m_swapChainStateVk->getVkImages()[imageIndex],
248         .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
249                              .baseMipLevel = 0,
250                              .levelCount = 1,
251                              .baseArrayLayer = 0,
252                              .layerCount = 1}};
253     m_vk.vkCmdPipelineBarrier(cmdBuff, VK_PIPELINE_STAGE_TRANSFER_BIT,
254                               VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
255                               &presentToXferDstBarrier);
256     VkImageBlit region = {
257         .srcSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
258                            .mipLevel = 0,
259                            .baseArrayLayer = 0,
260                            .layerCount = 1},
261         .srcOffsets = {{0, 0, 0},
262                        {static_cast<int32_t>(displayBufferPtr->m_vkImageCreateInfo.extent.width),
263                         static_cast<int32_t>(displayBufferPtr->m_vkImageCreateInfo.extent.height),
264                         1}},
265         .dstSubresource = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
266                            .mipLevel = 0,
267                            .baseArrayLayer = 0,
268                            .layerCount = 1},
269         .dstOffsets = {{0, 0, 0},
270                        {static_cast<int32_t>(m_surfaceState->m_width),
271                         static_cast<int32_t>(m_surfaceState->m_height), 1}},
272     };
273     VkFormat displayBufferFormat = displayBufferPtr->m_vkImageCreateInfo.format;
274     VkImageTiling displayBufferTiling = displayBufferPtr->m_vkImageCreateInfo.tiling;
275     VkFilter filter = VK_FILTER_NEAREST;
276     VkFormatFeatureFlags displayBufferFormatFeatures =
277         getFormatFeatures(displayBufferFormat, displayBufferTiling);
278     if (formatIsDepthOrStencil(displayBufferFormat)) {
279         DISPLAY_VK_ERROR_ONCE(
280             "The format of the display buffer, %s, is a depth/stencil format, we can only use the "
281             "VK_FILTER_NEAREST filter according to VUID-vkCmdBlitImage-srcImage-00232.",
282             string_VkFormat(displayBufferFormat));
283         filter = VK_FILTER_NEAREST;
284     } else if (!(displayBufferFormatFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
285         DISPLAY_VK_ERROR_ONCE(
286             "The format of the display buffer, %s, with the tiling, %s, doesn't support "
287             "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT, so we can only use the "
288             "VK_FILTER_NEAREST filter according VUID-vkCmdBlitImage-filter-02001. The supported "
289             "features are %s.",
290             string_VkFormat(displayBufferFormat), string_VkImageTiling(displayBufferTiling),
291             string_VkFormatFeatureFlags(displayBufferFormatFeatures).c_str());
292         filter = VK_FILTER_NEAREST;
293     } else {
294         filter = VK_FILTER_LINEAR;
295     }
296     m_vk.vkCmdBlitImage(cmdBuff, displayBufferPtr->m_vkImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
297                         m_swapChainStateVk->getVkImages()[imageIndex],
298                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region, filter);
299     VkImageMemoryBarrier xferDstToPresentBarrier = {
300         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
301         .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
302         .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
303         .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
304         .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
305         .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
306         .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
307         .image = m_swapChainStateVk->getVkImages()[imageIndex],
308         .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
309                              .baseMipLevel = 0,
310                              .levelCount = 1,
311                              .baseArrayLayer = 0,
312                              .layerCount = 1}};
313     m_vk.vkCmdPipelineBarrier(cmdBuff, VK_PIPELINE_STAGE_TRANSFER_BIT,
314                               VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1,
315                               &xferDstToPresentBarrier);
316     VK_CHECK(m_vk.vkEndCommandBuffer(cmdBuff));
317 
318     VkFence postCompleteFence = postResource->m_swapchainImageReleaseFence;
319     VK_CHECK(m_vk.vkResetFences(m_vkDevice, 1, &postCompleteFence));
320     VkSemaphore postCompleteSemaphore = postResource->m_swapchainImageReleaseSemaphore;
321     VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_TRANSFER_BIT};
322     VkSubmitInfo submitInfo = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
323                                .waitSemaphoreCount = 1,
324                                .pWaitSemaphores = &imageReadySem,
325                                .pWaitDstStageMask = waitStages,
326                                .commandBufferCount = 1,
327                                .pCommandBuffers = &cmdBuff,
328                                .signalSemaphoreCount = 1,
329                                .pSignalSemaphores = &postCompleteSemaphore};
330     {
331         android::base::AutoLock lock(*m_compositorVkQueueLock);
332         VK_CHECK(m_vk.vkQueueSubmit(m_compositorVkQueue, 1, &submitInfo, postCompleteFence));
333     }
334     std::shared_future<std::shared_ptr<PostResource>> postResourceFuture =
335         std::async(std::launch::deferred, [postCompleteFence, postResource, displayBufferPtr,
336                                            this]() mutable {
337             VK_CHECK(m_vk.vkWaitForFences(m_vkDevice, 1, &postCompleteFence, VK_TRUE, UINT64_MAX));
338             // Explicitly reset displayBufferPtr here to make sure the lambda actually capture
339             // displayBufferPtr to correctly extend the lifetime of displayBufferPtr until the
340             // rendering completes.
341             displayBufferPtr.reset();
342             return postResource;
343         }).share();
344     m_postResourceFuture = postResourceFuture;
345 
346     auto swapChain = m_swapChainStateVk->getSwapChain();
347     VkPresentInfoKHR presentInfo = {.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
348                                     .waitSemaphoreCount = 1,
349                                     .pWaitSemaphores = &postCompleteSemaphore,
350                                     .swapchainCount = 1,
351                                     .pSwapchains = &swapChain,
352                                     .pImageIndices = &imageIndex};
353     VkResult presentRes;
354     {
355         android::base::AutoLock lock(*m_swapChainVkQueueLock);
356         presentRes = m_vk.vkQueuePresentKHR(m_swapChainVkQueue, &presentInfo);
357     }
358     if (shouldRecreateSwapchain(presentRes)) {
359         postResourceFuture.wait();
360         return std::make_tuple(false, std::shared_future<void>());
361     }
362     VK_CHECK(presentRes);
363     return std::make_tuple(true, std::async(std::launch::deferred, [postResourceFuture] {
364                                      // We can't directly wait for the VkFence here, because we
365                                      // share the VkFences on different frames, but we don't share
366                                      // the future on different frames. If we directly wait for the
367                                      // VkFence here, we may wait for a different frame if a new
368                                      // frame starts to be drawn before this future is waited.
369                                      postResourceFuture.wait();
370                                  }).share());
371 }
372 
compose(uint32_t numLayers,const ComposeLayer layers[],std::vector<std::shared_ptr<DisplayBufferInfo>> composeBuffers,std::shared_ptr<DisplayBufferInfo> targetBuffer)373 std::tuple<bool, std::shared_future<void>> DisplayVk::compose(
374     uint32_t numLayers, const ComposeLayer layers[],
375     std::vector<std::shared_ptr<DisplayBufferInfo>> composeBuffers,
376     std::shared_ptr<DisplayBufferInfo> targetBuffer) {
377     std::shared_future<void> completedFuture = std::async(std::launch::deferred, [] {}).share();
378     completedFuture.wait();
379 
380     if (!m_swapChainStateVk || !m_compositorVk) {
381         DISPLAY_VK_ERROR("Haven't bound to a surface, can't compose color buffer.");
382         // The surface hasn't been created yet, hence we don't return
383         // std::nullopt to request rebinding.
384         return std::make_tuple(true, std::move(completedFuture));
385     }
386 
387     std::vector<std::unique_ptr<ComposeLayerVk>> composeLayers;
388     for (int i = 0; i < numLayers; ++i) {
389         if (layers[i].cbHandle == 0) {
390             // When ColorBuffer handle is 0, it's expected that no ColorBuffer
391             // is not found.
392             continue;
393         }
394         if (!composeBuffers[i]) {
395             DISPLAY_VK_ERROR("warning: null ptr passed to compose buffer for layer %d.", i);
396             continue;
397         }
398         const auto& db = *composeBuffers[i];
399         if (!canCompositeFrom(db.m_vkImageCreateInfo)) {
400             DISPLAY_VK_ERROR("Can't composite from a display buffer. Skip the layer.");
401             continue;
402         }
403         auto layer = ComposeLayerVk::createFromHwc2ComposeLayer(
404             m_compositionVkSampler, composeBuffers[i]->m_vkImageView, layers[i],
405             composeBuffers[i]->m_vkImageCreateInfo.extent.width,
406             composeBuffers[i]->m_vkImageCreateInfo.extent.height,
407             targetBuffer->m_vkImageCreateInfo.extent.width,
408             targetBuffer->m_vkImageCreateInfo.extent.height);
409         composeLayers.emplace_back(std::move(layer));
410     }
411 
412     if (composeLayers.empty()) {
413         return std::make_tuple(true, std::move(completedFuture));
414     }
415 
416     if (!targetBuffer) {
417         DISPLAY_VK_ERROR("warning null ptr passed to compose target.");
418         return std::make_tuple(true, std::move(completedFuture));
419     }
420     if (!canCompositeTo(targetBuffer->m_vkImageCreateInfo)) {
421         DISPLAY_VK_ERROR("Can't write the result of the composition to the display buffer.");
422         return std::make_tuple(true, std::move(completedFuture));
423     }
424 
425     std::shared_ptr<CompositorVkRenderTarget> compositorVkRenderTarget =
426         targetBuffer->m_compositorVkRenderTarget.lock();
427     if (!compositorVkRenderTarget) {
428         compositorVkRenderTarget = m_compositorVk->createRenderTarget(
429             targetBuffer->m_vkImageView, targetBuffer->m_vkImageCreateInfo.extent.width,
430             targetBuffer->m_vkImageCreateInfo.extent.height);
431         if (!compositorVkRenderTarget) {
432             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
433                 << "Failed to create CompositorVkRenderTarget for the target display buffer.";
434         }
435         m_compositorVkRenderTargets.pop_back();
436         m_compositorVkRenderTargets.push_front(compositorVkRenderTarget);
437         targetBuffer->m_compositorVkRenderTarget = compositorVkRenderTarget;
438     }
439 
440     std::future<std::unique_ptr<ComposeResource>> composeResourceFuture =
441         std::move(m_composeResourceFuture.value());
442     if (!composeResourceFuture.valid()) {
443         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
444             << "Invalid composeResourceFuture in m_postResourceFutures.";
445     }
446     std::unique_ptr<ComposeResource> composeResource = composeResourceFuture.get();
447 
448     if (compareAndSaveComposition(m_inFlightFrameIndex, numLayers, layers, composeBuffers)) {
449         auto composition = std::make_unique<Composition>(std::move(composeLayers));
450         m_compositorVk->setComposition(m_inFlightFrameIndex, std::move(composition));
451     }
452 
453     VkCommandBuffer cmdBuff = composeResource->m_vkCommandBuffer;
454     VK_CHECK(m_vk.vkResetCommandBuffer(cmdBuff, 0));
455 
456     VkCommandBufferBeginInfo beginInfo = {
457         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
458         .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
459     };
460     VK_CHECK(m_vk.vkBeginCommandBuffer(cmdBuff, &beginInfo));
461     m_compositorVk->recordCommandBuffers(m_inFlightFrameIndex, cmdBuff, *compositorVkRenderTarget);
462     // Insert a VkImageMemoryBarrier so that the vkCmdBlitImage in post will wait for the rendering
463     // to the render target to complete.
464     VkImageMemoryBarrier renderTargetBarrier = {
465         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
466         .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
467         .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
468         .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
469         .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
470         .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
471         .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
472         .image = targetBuffer->m_vkImage,
473         .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
474                              .baseMipLevel = 0,
475                              .levelCount = 1,
476                              .baseArrayLayer = 0,
477                              .layerCount = 1}};
478     m_vk.vkCmdPipelineBarrier(cmdBuff, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
479                               VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
480                               &renderTargetBarrier);
481     VK_CHECK(m_vk.vkEndCommandBuffer(cmdBuff));
482 
483     VkFence composeCompleteFence = composeResource->m_composeCompleteFence;
484     VK_CHECK(m_vk.vkResetFences(m_vkDevice, 1, &composeCompleteFence));
485     VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_TRANSFER_BIT};
486     VkSubmitInfo submitInfo = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
487                                .waitSemaphoreCount = 0,
488                                .pWaitSemaphores = nullptr,
489                                .pWaitDstStageMask = waitStages,
490                                .commandBufferCount = 1,
491                                .pCommandBuffers = &cmdBuff,
492                                .signalSemaphoreCount = 0,
493                                .pSignalSemaphores = nullptr};
494     {
495         android::base::AutoLock lock(*m_compositorVkQueueLock);
496         VK_CHECK(m_vk.vkQueueSubmit(m_compositorVkQueue, 1, &submitInfo, composeCompleteFence));
497     }
498 
499     m_composeResourceFuture =
500         std::async(std::launch::deferred,
501                    [composeCompleteFence, composeResource = std::move(composeResource),
502                     composeBuffers = std::move(composeBuffers), targetBuffer, this]() mutable {
503                        VK_CHECK(m_vk.vkWaitForFences(m_vkDevice, 1, &composeCompleteFence, VK_TRUE,
504                                                      UINT64_MAX));
505                        // Explicitly clear the composeBuffers here to ensure the lambda does
506                        // caputure composeBuffers and correctly extend the lifetime of related
507                        // DisplayBufferInfo until the render completes.
508                        composeBuffers.clear();
509                        // Explicitly reset the targetBuffer here to ensure the lambda does caputure
510                        // targetBuffer and correctly extend the lifetime of the DisplayBufferInfo
511                        // until the render completes.
512                        targetBuffer.reset();
513                        return std::move(composeResource);
514                    });
515     m_inFlightFrameIndex = (m_inFlightFrameIndex + 1) % m_swapChainStateVk->getVkImages().size();
516     return post(targetBuffer);
517 }
518 
getFormatFeatures(VkFormat format,VkImageTiling tiling)519 VkFormatFeatureFlags DisplayVk::getFormatFeatures(VkFormat format, VkImageTiling tiling) {
520     auto i = m_vkFormatProperties.find(format);
521     if (i == m_vkFormatProperties.end()) {
522         VkFormatProperties formatProperties;
523         m_vk.vkGetPhysicalDeviceFormatProperties(m_vkPhysicalDevice, format, &formatProperties);
524         i = m_vkFormatProperties.emplace(format, formatProperties).first;
525     }
526     const VkFormatProperties& formatProperties = i->second;
527     VkFormatFeatureFlags formatFeatures = 0;
528     if (tiling == VK_IMAGE_TILING_LINEAR) {
529         formatFeatures = formatProperties.linearTilingFeatures;
530     } else if (tiling == VK_IMAGE_TILING_OPTIMAL) {
531         formatFeatures = formatProperties.optimalTilingFeatures;
532     } else {
533         DISPLAY_VK_ERROR("Unknown tiling %#" PRIx64 ".", static_cast<uint64_t>(tiling));
534     }
535     return formatFeatures;
536 }
537 
canPost(const VkImageCreateInfo & postImageCi)538 bool DisplayVk::canPost(const VkImageCreateInfo& postImageCi) {
539     // According to VUID-vkCmdBlitImage-srcImage-01999, the format features of srcImage must contain
540     // VK_FORMAT_FEATURE_BLIT_SRC_BIT.
541     VkFormatFeatureFlags formatFeatures = getFormatFeatures(postImageCi.format, postImageCi.tiling);
542     if (!(formatFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) {
543         DISPLAY_VK_ERROR(
544             "VK_FORMAT_FEATURE_BLIT_SRC_BLIT is not supported for VkImage with format %s, tilling "
545             "%s. Supported features are %s.",
546             string_VkFormat(postImageCi.format), string_VkImageTiling(postImageCi.tiling),
547             string_VkFormatFeatureFlags(formatFeatures).c_str());
548         return false;
549     }
550 
551     // According to VUID-vkCmdBlitImage-srcImage-06421, srcImage must not use a format that requires
552     // a sampler Y’CBCR conversion.
553     if (formatRequiresSamplerYcbcrConversion(postImageCi.format)) {
554         DISPLAY_VK_ERROR("Format %s requires a sampler Y'CbCr conversion. Can't be used to post.",
555                          string_VkFormat(postImageCi.format));
556         return false;
557     }
558 
559     if (!(postImageCi.usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
560         // According to VUID-vkCmdBlitImage-srcImage-00219, srcImage must have been created with
561         // VK_IMAGE_USAGE_TRANSFER_SRC_BIT usage flag.
562         DISPLAY_VK_ERROR(
563             "The VkImage is not created with the VK_IMAGE_USAGE_TRANSFER_SRC_BIT usage flag. The "
564             "usage flags are %s.",
565             string_VkImageUsageFlags(postImageCi.usage).c_str());
566         return false;
567     }
568 
569     VkFormat swapChainFormat = m_swapChainStateVk->getFormat();
570     if (formatIsSInt(postImageCi.format) || formatIsSInt(swapChainFormat)) {
571         // According to VUID-vkCmdBlitImage-srcImage-00229, if either of srcImage or dstImage was
572         // created with a signed integer VkFormat, the other must also have been created with a
573         // signed integer VkFormat.
574         if (!(formatIsSInt(postImageCi.format) && formatIsSInt(m_swapChainStateVk->getFormat()))) {
575             DISPLAY_VK_ERROR(
576                 "The format(%s) doesn't match with the format of the presentable image(%s): either "
577                 "of the formats is a signed integer VkFormat, but the other is not.",
578                 string_VkFormat(postImageCi.format), string_VkFormat(swapChainFormat));
579             return false;
580         }
581     }
582 
583     if (formatIsUInt(postImageCi.format) || formatIsUInt(swapChainFormat)) {
584         // According to VUID-vkCmdBlitImage-srcImage-00230, if either of srcImage or dstImage was
585         // created with an unsigned integer VkFormat, the other must also have been created with an
586         // unsigned integer VkFormat.
587         if (!(formatIsUInt(postImageCi.format) && formatIsUInt(swapChainFormat))) {
588             DISPLAY_VK_ERROR(
589                 "The format(%s) doesn't match with the format of the presentable image(%s): either "
590                 "of the formats is an unsigned integer VkFormat, but the other is not.",
591                 string_VkFormat(postImageCi.format), string_VkFormat(swapChainFormat));
592             return false;
593         }
594     }
595 
596     if (formatIsDepthOrStencil(postImageCi.format) || formatIsDepthOrStencil(swapChainFormat)) {
597         // According to VUID-vkCmdBlitImage-srcImage-00231, if either of srcImage or dstImage was
598         // created with a depth/stencil format, the other must have exactly the same format.
599         if (postImageCi.format != swapChainFormat) {
600             DISPLAY_VK_ERROR(
601                 "The format(%s) doesn't match with the format of the presentable image(%s): either "
602                 "of the formats is a depth/stencil VkFormat, but the other is not the same format.",
603                 string_VkFormat(postImageCi.format), string_VkFormat(swapChainFormat));
604             return false;
605         }
606     }
607 
608     if (postImageCi.samples != VK_SAMPLE_COUNT_1_BIT) {
609         // According to VUID-vkCmdBlitImage-srcImage-00233, srcImage must have been created with a
610         // samples value of VK_SAMPLE_COUNT_1_BIT.
611         DISPLAY_VK_ERROR(
612             "The VkImage is not created with the VK_SAMPLE_COUNT_1_BIT samples value. The samples "
613             "value is %s.",
614             string_VkSampleCountFlagBits(postImageCi.samples));
615         return false;
616     }
617     if (postImageCi.flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT) {
618         // According to VUID-vkCmdBlitImage-dstImage-02545, dstImage and srcImage must not have been
619         // created with flags containing VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT.
620         DISPLAY_VK_ERROR(
621             "The VkImage can't be created with flags containing "
622             "VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT. The flags are %s.",
623             string_VkImageCreateFlags(postImageCi.flags).c_str());
624         return false;
625     }
626     return true;
627 }
628 
canCompositeFrom(const VkImageCreateInfo & imageCi)629 bool DisplayVk::canCompositeFrom(const VkImageCreateInfo& imageCi) {
630     VkFormatFeatureFlags formatFeatures = getFormatFeatures(imageCi.format, imageCi.tiling);
631     if (!(formatFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
632         DISPLAY_VK_ERROR(
633             "The format, %s, with tiling, %s, doesn't support the "
634             "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT feature. All supported features are %s.",
635             string_VkFormat(imageCi.format), string_VkImageTiling(imageCi.tiling),
636             string_VkFormatFeatureFlags(formatFeatures).c_str());
637         return false;
638     }
639     return true;
640 }
641 
canCompositeTo(const VkImageCreateInfo & imageCi)642 bool DisplayVk::canCompositeTo(const VkImageCreateInfo& imageCi) {
643     VkFormatFeatureFlags formatFeatures = getFormatFeatures(imageCi.format, imageCi.tiling);
644     if (!(formatFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
645         DISPLAY_VK_ERROR(
646             "The format, %s, with tiling, %s, doesn't support the "
647             "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT feature. All supported features are %s.",
648             string_VkFormat(imageCi.format), string_VkImageTiling(imageCi.tiling),
649             string_VkFormatFeatureFlags(formatFeatures).c_str());
650         return false;
651     }
652     if (!(imageCi.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
653         DISPLAY_VK_ERROR(
654             "The VkImage is not created with the VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT usage flag. "
655             "The usage flags are %s.",
656             string_VkImageUsageFlags(imageCi.usage).c_str());
657         return false;
658     }
659     if (imageCi.format != k_compositorVkRenderTargetFormat) {
660         DISPLAY_VK_ERROR(
661             "The format of the image, %s, is not supported by the CompositorVk as the render "
662             "target.",
663             string_VkFormat(imageCi.format));
664         return false;
665     }
666     return true;
667 }
668 
compareAndSaveComposition(uint32_t renderTargetIndex,uint32_t numLayers,const ComposeLayer layers[],const std::vector<std::shared_ptr<DisplayBufferInfo>> & composeBuffers)669 bool DisplayVk::compareAndSaveComposition(
670     uint32_t renderTargetIndex, uint32_t numLayers, const ComposeLayer layers[],
671     const std::vector<std::shared_ptr<DisplayBufferInfo>>& composeBuffers) {
672     if (!m_surfaceState) {
673         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
674             << "Haven't bound to a surface, can't compare and save composition.";
675     }
676     auto [iPrevComposition, compositionNotFound] =
677         m_surfaceState->m_prevCompositions.emplace(renderTargetIndex, 0);
678     auto& prevComposition = iPrevComposition->second;
679     bool compositionChanged = false;
680     if (numLayers == prevComposition.size()) {
681         for (int i = 0; i < numLayers; i++) {
682             if (composeBuffers[i] == nullptr) {
683                 // If the display buffer of the current layer doesn't exist, we
684                 // check if the layer at the same index in the previous
685                 // composition doesn't exist either.
686                 if (prevComposition[i] == nullptr) {
687                     continue;
688                 } else {
689                     compositionChanged = true;
690                     break;
691                 }
692             }
693             if (prevComposition[i] == nullptr) {
694                 // If the display buffer of the current layer exists but the
695                 // layer at the same index in the previous composition doesn't
696                 // exist, the composition is changed.
697                 compositionChanged = true;
698                 break;
699             }
700             const auto& prevLayer = *prevComposition[i];
701             const auto prevDisplayBufferPtr = prevLayer.m_displayBuffer.lock();
702             // prevLayer.m_displayBuffer is a weak pointer, so if
703             // prevDisplayBufferPtr is null, the color buffer
704             // prevDisplayBufferPtr pointed to should have been released or
705             // re-allocated, and we should consider the composition is changed.
706             // If prevDisplayBufferPtr exists and it points to the same display
707             // buffer as the input composeBuffers[i] we consider the composition
708             // not changed.
709             if (!prevDisplayBufferPtr || prevDisplayBufferPtr != composeBuffers[i]) {
710                 compositionChanged = true;
711                 break;
712             }
713             const auto& prevHwc2Layer = prevLayer.m_hwc2Layer;
714             const auto hwc2Layer = layers[i];
715             compositionChanged =
716                 (prevHwc2Layer.cbHandle != hwc2Layer.cbHandle) ||
717                 (prevHwc2Layer.composeMode != hwc2Layer.composeMode) ||
718                 (prevHwc2Layer.displayFrame.left != hwc2Layer.displayFrame.left) ||
719                 (prevHwc2Layer.displayFrame.top != hwc2Layer.displayFrame.top) ||
720                 (prevHwc2Layer.displayFrame.right != hwc2Layer.displayFrame.right) ||
721                 (prevHwc2Layer.displayFrame.bottom != hwc2Layer.displayFrame.bottom) ||
722                 (prevHwc2Layer.crop.left != hwc2Layer.crop.left) ||
723                 (prevHwc2Layer.crop.top != hwc2Layer.crop.top) ||
724                 (prevHwc2Layer.crop.right != hwc2Layer.crop.right) ||
725                 (prevHwc2Layer.crop.bottom != hwc2Layer.crop.bottom) ||
726                 (prevHwc2Layer.blendMode != hwc2Layer.blendMode) ||
727                 (prevHwc2Layer.alpha != hwc2Layer.alpha) ||
728                 (prevHwc2Layer.color.r != hwc2Layer.color.r) ||
729                 (prevHwc2Layer.color.g != hwc2Layer.color.g) ||
730                 (prevHwc2Layer.color.b != hwc2Layer.color.b) ||
731                 (prevHwc2Layer.color.a != hwc2Layer.color.a) ||
732                 (prevHwc2Layer.transform != hwc2Layer.transform);
733             if (compositionChanged) {
734                 break;
735             }
736         }
737     } else {
738         compositionChanged = true;
739     }
740     bool needsSave = compositionNotFound || compositionChanged;
741     if (needsSave) {
742         prevComposition.clear();
743         for (int i = 0; i < numLayers; i++) {
744             if (composeBuffers[i] == nullptr) {
745                 prevComposition.emplace_back(nullptr);
746                 continue;
747             }
748             auto layer = std::make_unique<SurfaceState::Layer>();
749             layer->m_hwc2Layer = layers[i];
750             layer->m_displayBuffer = composeBuffers[i];
751             prevComposition.emplace_back(std::move(layer));
752         }
753     }
754     return needsSave;
755 }
756 
DisplayBufferInfo(const goldfish_vk::VulkanDispatch & vk,VkDevice vkDevice,const VkImageCreateInfo & vkImageCreateInfo,VkImage image)757 DisplayVk::DisplayBufferInfo::DisplayBufferInfo(const goldfish_vk::VulkanDispatch& vk,
758                                                 VkDevice vkDevice,
759                                                 const VkImageCreateInfo& vkImageCreateInfo,
760                                                 VkImage image)
761     : m_vk(vk),
762       m_vkDevice(vkDevice),
763       m_vkImageCreateInfo(vk_make_orphan_copy(vkImageCreateInfo)),
764       m_vkImage(image),
765       m_vkImageView(VK_NULL_HANDLE),
766       m_compositorVkRenderTarget() {
767     VkImageViewCreateInfo imageViewCi = {
768         .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
769         .image = image,
770         .viewType = VK_IMAGE_VIEW_TYPE_2D,
771         .format = m_vkImageCreateInfo.format,
772         .components = {.r = VK_COMPONENT_SWIZZLE_IDENTITY,
773                        .g = VK_COMPONENT_SWIZZLE_IDENTITY,
774                        .b = VK_COMPONENT_SWIZZLE_IDENTITY,
775                        .a = VK_COMPONENT_SWIZZLE_IDENTITY},
776         .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
777                              .baseMipLevel = 0,
778                              .levelCount = 1,
779                              .baseArrayLayer = 0,
780                              .layerCount = 1}};
781     VK_CHECK(m_vk.vkCreateImageView(m_vkDevice, &imageViewCi, nullptr, &m_vkImageView));
782 }
783 
~DisplayBufferInfo()784 DisplayVk::DisplayBufferInfo::~DisplayBufferInfo() {
785     m_vk.vkDestroyImageView(m_vkDevice, m_vkImageView, nullptr);
786 }
787 
create(const goldfish_vk::VulkanDispatch & vk,VkDevice vkDevice,VkCommandPool vkCommandPool)788 std::shared_ptr<DisplayVk::PostResource> DisplayVk::PostResource::create(
789     const goldfish_vk::VulkanDispatch &vk, VkDevice vkDevice, VkCommandPool vkCommandPool) {
790     VkFenceCreateInfo fenceCi = {
791         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
792     };
793     VkFence fence;
794     VK_CHECK(vk.vkCreateFence(vkDevice, &fenceCi, nullptr, &fence));
795     VkSemaphore semaphores[2];
796     for (uint32_t i = 0; i < std::size(semaphores); i++) {
797         VkSemaphoreCreateInfo semaphoreCi = {
798             .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
799         };
800         VK_CHECK(vk.vkCreateSemaphore(vkDevice, &semaphoreCi, nullptr, &semaphores[i]));
801     }
802     VkCommandBuffer commandBuffer;
803     VkCommandBufferAllocateInfo commandBufferAllocInfo = {
804         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
805         .commandPool = vkCommandPool,
806         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
807         .commandBufferCount = 1,
808     };
809     VK_CHECK(vk.vkAllocateCommandBuffers(vkDevice, &commandBufferAllocInfo, &commandBuffer));
810     return std::shared_ptr<PostResource>(new PostResource(
811         vk, vkDevice, vkCommandPool, fence, semaphores[0], semaphores[1], commandBuffer));
812 }
813 
~PostResource()814 DisplayVk::PostResource::~PostResource() {
815     m_vk.vkFreeCommandBuffers(m_vkDevice, m_vkCommandPool, 1, &m_vkCommandBuffer);
816     m_vk.vkDestroyFence(m_vkDevice, m_swapchainImageReleaseFence, nullptr);
817     m_vk.vkDestroySemaphore(m_vkDevice, m_swapchainImageAcquireSemaphore, nullptr);
818     m_vk.vkDestroySemaphore(m_vkDevice, m_swapchainImageReleaseSemaphore, nullptr);
819 }
820 
PostResource(const goldfish_vk::VulkanDispatch & vk,VkDevice vkDevice,VkCommandPool vkCommandPool,VkFence swapchainImageReleaseFence,VkSemaphore swapchainImageAcquireSemaphore,VkSemaphore swapchainImageReleaseSemaphore,VkCommandBuffer vkCommandBuffer)821 DisplayVk::PostResource::PostResource(const goldfish_vk::VulkanDispatch& vk, VkDevice vkDevice,
822                                       VkCommandPool vkCommandPool,
823                                       VkFence swapchainImageReleaseFence,
824                                       VkSemaphore swapchainImageAcquireSemaphore,
825                                       VkSemaphore swapchainImageReleaseSemaphore,
826                                       VkCommandBuffer vkCommandBuffer)
827     : m_swapchainImageReleaseFence(swapchainImageReleaseFence),
828       m_swapchainImageAcquireSemaphore(swapchainImageAcquireSemaphore),
829       m_swapchainImageReleaseSemaphore(swapchainImageReleaseSemaphore),
830       m_vkCommandBuffer(vkCommandBuffer),
831       m_vk(vk),
832       m_vkDevice(vkDevice),
833       m_vkCommandPool(vkCommandPool) {}
834 
create(const goldfish_vk::VulkanDispatch & vk,VkDevice vkDevice,VkCommandPool vkCommandPool)835 std::unique_ptr<DisplayVk::ComposeResource> DisplayVk::ComposeResource::create(
836     const goldfish_vk::VulkanDispatch &vk, VkDevice vkDevice, VkCommandPool vkCommandPool) {
837     VkFenceCreateInfo fenceCi = {
838         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
839     };
840     VkFence fence;
841     VK_CHECK(vk.vkCreateFence(vkDevice, &fenceCi, nullptr, &fence));
842 
843     VkCommandBuffer commandBuffer;
844     VkCommandBufferAllocateInfo commandBufferAllocInfo = {
845         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
846         .commandPool = vkCommandPool,
847         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
848         .commandBufferCount = 1,
849     };
850     VK_CHECK(vk.vkAllocateCommandBuffers(vkDevice, &commandBufferAllocInfo, &commandBuffer));
851 
852     return std::unique_ptr<ComposeResource>(
853         new ComposeResource(vk, vkDevice, vkCommandPool, fence, commandBuffer));
854 }
855 
~ComposeResource()856 DisplayVk::ComposeResource::~ComposeResource() {
857     m_vk.vkFreeCommandBuffers(m_vkDevice, m_vkCommandPool, 1, &m_vkCommandBuffer);
858     m_vk.vkDestroyFence(m_vkDevice, m_composeCompleteFence, nullptr);
859 }
860 
ComposeResource(const goldfish_vk::VulkanDispatch & vk,VkDevice vkDevice,VkCommandPool vkCommandPool,VkFence composeCompleteFence,VkCommandBuffer vkCommandBuffer)861 DisplayVk::ComposeResource::ComposeResource(const goldfish_vk::VulkanDispatch& vk,
862                                             VkDevice vkDevice, VkCommandPool vkCommandPool,
863                                             VkFence composeCompleteFence,
864                                             VkCommandBuffer vkCommandBuffer)
865     : m_composeCompleteFence(composeCompleteFence),
866       m_vkCommandBuffer(vkCommandBuffer),
867       m_vk(vk),
868       m_vkDevice(vkDevice),
869       m_vkCommandPool(vkCommandPool) {}
870