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