1 // Copyright 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expresso or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 #include "VkAndroidNativeBuffer.h"
14 
15 #include <string.h>
16 
17 #include <future>
18 
19 #include "FrameBuffer.h"
20 #include "GrallocDefs.h"
21 #include "SyncThread.h"
22 #include "VkCommonOperations.h"
23 #include "VulkanDispatch.h"
24 #include "cereal/common/goldfish_vk_deepcopy.h"
25 #include "cereal/common/goldfish_vk_extension_structs.h"
26 #include "gfxstream/host/BackendCallbacks.h"
27 #include "gfxstream/host/Tracing.h"
28 #include "goldfish_vk_private_defs.h"
29 #include "host-common/GfxstreamFatalError.h"
30 #include "vulkan/vk_enum_string_helper.h"
31 
32 namespace gfxstream {
33 namespace vk {
34 
35 #define VK_ANB_ERR(fmt, ...) INFO(fmt, ##__VA_ARGS__);
36 
37 #define ENABLE_VK_ANB_DEBUG 0
38 
39 #if ENABLE_VK_ANB_DEBUG
40 #define VK_ANB_DEBUG(fmt, ...) \
41     INFO("vk-anb-debug: " fmt, ##__VA_ARGS__);
42 #define VK_ANB_DEBUG_OBJ(obj, fmt, ...) \
43     INFO("vk-anb-debug: %p " fmt, obj, ##__VA_ARGS__);
44 #else
45 #define VK_ANB_DEBUG(fmt, ...)
46 #define VK_ANB_DEBUG_OBJ(obj, fmt, ...)
47 #endif
48 
49 using android::base::AutoLock;
50 using android::base::Lock;
51 using emugl::ABORT_REASON_OTHER;
52 using emugl::FatalError;
53 
QsriWaitFencePool(VulkanDispatch * vk,VkDevice device)54 AndroidNativeBufferInfo::QsriWaitFencePool::QsriWaitFencePool(VulkanDispatch* vk, VkDevice device)
55     : mVk(vk), mDevice(device) {}
56 
getFenceFromPool()57 VkFence AndroidNativeBufferInfo::QsriWaitFencePool::getFenceFromPool() {
58     VK_ANB_DEBUG("enter");
59     AutoLock lock(mLock);
60     VkFence fence = VK_NULL_HANDLE;
61     if (mAvailableFences.empty()) {
62         VkFenceCreateInfo fenceCreateInfo = {
63             VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
64             0,
65             0,
66         };
67         mVk->vkCreateFence(mDevice, &fenceCreateInfo, nullptr, &fence);
68         VK_ANB_DEBUG("no fences in pool, created %p", fence);
69     } else {
70         fence = mAvailableFences.back();
71         mAvailableFences.pop_back();
72         VkResult res = mVk->vkResetFences(mDevice, 1, &fence);
73         if (res != VK_SUCCESS) {
74             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
75                 << "Fail to reset Qsri VkFence: " << res << "(" << string_VkResult(res) << ").";
76         }
77         VK_ANB_DEBUG("existing fence in pool: %p. also reset the fence", fence);
78     }
79     mUsedFences.emplace(fence);
80     VK_ANB_DEBUG("exit");
81     return fence;
82 }
83 
~QsriWaitFencePool()84 AndroidNativeBufferInfo::QsriWaitFencePool::~QsriWaitFencePool() {
85     VK_ANB_DEBUG("enter");
86     // Nothing in the fence pool is unsignaled
87     if (!mUsedFences.empty()) {
88         VK_ANB_ERR("%zu VkFences are still being used when destroying the Qsri fence pool.",
89                    mUsedFences.size());
90     }
91     for (auto fence : mAvailableFences) {
92         VK_ANB_DEBUG("destroy fence %p", fence);
93         mVk->vkDestroyFence(mDevice, fence, nullptr);
94     }
95     VK_ANB_DEBUG("exit");
96 }
97 
returnFence(VkFence fence)98 void AndroidNativeBufferInfo::QsriWaitFencePool::returnFence(VkFence fence) {
99     AutoLock lock(mLock);
100     if (!mUsedFences.erase(fence)) {
101         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
102             << "Return an unmanaged Qsri VkFence back to the pool.";
103         return;
104     }
105     mAvailableFences.push_back(fence);
106 }
107 
parseAndroidNativeBufferInfo(const VkImageCreateInfo * pCreateInfo,AndroidNativeBufferInfo * info_out)108 bool parseAndroidNativeBufferInfo(const VkImageCreateInfo* pCreateInfo,
109                                   AndroidNativeBufferInfo* info_out) {
110     // Look through the extension chain.
111     const void* curr_pNext = pCreateInfo->pNext;
112     if (!curr_pNext) return false;
113 
114     uint32_t structType = goldfish_vk_struct_type(curr_pNext);
115 
116     return structType == VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID;
117 }
118 
prepareAndroidNativeBufferImage(VulkanDispatch * vk,VkDevice device,android::base::BumpPool & allocator,const VkImageCreateInfo * pCreateInfo,const VkNativeBufferANDROID * nativeBufferANDROID,const VkAllocationCallbacks * pAllocator,const VkPhysicalDeviceMemoryProperties * memProps,AndroidNativeBufferInfo * out)119 VkResult prepareAndroidNativeBufferImage(VulkanDispatch* vk, VkDevice device,
120                                          android::base::BumpPool& allocator,
121                                          const VkImageCreateInfo* pCreateInfo,
122                                          const VkNativeBufferANDROID* nativeBufferANDROID,
123                                          const VkAllocationCallbacks* pAllocator,
124                                          const VkPhysicalDeviceMemoryProperties* memProps,
125                                          AndroidNativeBufferInfo* out) {
126     bool colorBufferExportedToGl = false;
127     bool externalMemoryCompatible = false;
128 
129     out->vk = vk;
130     out->device = device;
131     out->vkFormat = pCreateInfo->format;
132     out->extent = pCreateInfo->extent;
133     out->usage = pCreateInfo->usage;
134 
135     for (uint32_t i = 0; i < pCreateInfo->queueFamilyIndexCount; ++i) {
136         out->queueFamilyIndices.push_back(pCreateInfo->pQueueFamilyIndices[i]);
137     }
138 
139     out->format = nativeBufferANDROID->format;
140     out->stride = nativeBufferANDROID->stride;
141     out->colorBufferHandle = *static_cast<const uint32_t*>(nativeBufferANDROID->handle);
142 
143     auto emu = getGlobalVkEmulation();
144 
145     if (!getColorBufferShareInfo(out->colorBufferHandle, &colorBufferExportedToGl,
146                                  &externalMemoryCompatible)) {
147         VK_ANB_ERR("Failed to query if ColorBuffer:%d exported to GL.", out->colorBufferHandle);
148         return VK_ERROR_INITIALIZATION_FAILED;
149     }
150 
151     if (externalMemoryCompatible) {
152         releaseColorBufferForGuestUse(out->colorBufferHandle);
153         out->externallyBacked = true;
154     }
155 
156     out->useVulkanNativeImage =
157         (emu && emu->live && emu->guestVulkanOnly) || colorBufferExportedToGl;
158 
159     VkDeviceSize bindOffset = 0;
160     if (out->externallyBacked) {
161         VkImageCreateInfo createImageCi;
162         deepcopy_VkImageCreateInfo(&allocator, VK_STRUCTURE_TYPE_MAX_ENUM, pCreateInfo,
163                                    &createImageCi);
164         auto* nativeBufferAndroid = vk_find_struct<VkNativeBufferANDROID>(&createImageCi);
165         if (!nativeBufferAndroid) {
166             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
167                 << "VkNativeBufferANDROID is required to be included in the pNext chain of the "
168                    "VkImageCreateInfo when importing a gralloc buffer.";
169         }
170         vk_struct_chain_remove(nativeBufferAndroid, &createImageCi);
171 
172         // VkBindImageMemorySwapchainInfoKHR should also not be passed to image creation
173         auto* bindSwapchainInfo = vk_find_struct<VkBindImageMemorySwapchainInfoKHR>(&createImageCi);
174         vk_struct_chain_remove(bindSwapchainInfo, &createImageCi);
175 
176         if (vk_find_struct<VkExternalMemoryImageCreateInfo>(&createImageCi)) {
177             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
178                 << "Unhandled VkExternalMemoryImageCreateInfo in the pNext chain.";
179         }
180         // Create the image with extension structure about external backing.
181         VkExternalMemoryImageCreateInfo extImageCi = {
182             VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
183             0,
184             VK_EXT_MEMORY_HANDLE_TYPE_BIT,
185         };
186 
187 #if defined(__APPLE__)
188         if (emu->instanceSupportsMoltenVK) {
189             // Change handle type requested to metal handle
190             extImageCi.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
191         }
192 #endif
193 
194         vk_insert_struct(createImageCi, extImageCi);
195 
196         VkResult createResult = vk->vkCreateImage(device, &createImageCi, pAllocator, &out->image);
197 
198         if (createResult != VK_SUCCESS) return createResult;
199 
200         // Now import the backing memory.
201         const auto& cbInfo = getColorBufferInfo(out->colorBufferHandle);
202         const auto& memInfo = cbInfo.memory;
203 
204         vk->vkGetImageMemoryRequirements(device, out->image, &out->memReqs);
205 
206         if (out->memReqs.size < memInfo.size) {
207             out->memReqs.size = memInfo.size;
208         }
209 
210         if (memInfo.dedicatedAllocation) {
211             if (!importExternalMemoryDedicatedImage(vk, device, &memInfo, out->image,
212                                                     &out->imageMemory)) {
213                 VK_ANB_ERR(
214                     "VK_ANDROID_native_buffer: Failed to import external memory (dedicated)");
215                 return VK_ERROR_INITIALIZATION_FAILED;
216             }
217         } else {
218             if (!importExternalMemory(vk, device, &memInfo, &out->imageMemory)) {
219                 VK_ANB_ERR("VK_ANDROID_native_buffer: Failed to import external memory");
220                 return VK_ERROR_INITIALIZATION_FAILED;
221             }
222         }
223 
224         bindOffset = memInfo.bindOffset;
225     } else {
226         // delete the info struct and pass to vkCreateImage, and also add
227         // transfer src capability to allow us to copy to CPU.
228         VkImageCreateInfo infoNoNative = *pCreateInfo;
229         infoNoNative.pNext = nullptr;
230         infoNoNative.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
231         VkResult createResult = vk->vkCreateImage(device, &infoNoNative, pAllocator, &out->image);
232 
233         if (createResult != VK_SUCCESS) return createResult;
234 
235         vk->vkGetImageMemoryRequirements(device, out->image, &out->memReqs);
236 
237         uint32_t imageMemoryTypeIndex = 0;
238         bool imageMemoryTypeIndexFound = false;
239 
240         for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) {
241             bool supported = out->memReqs.memoryTypeBits & (1 << i);
242             if (supported) {
243                 imageMemoryTypeIndex = i;
244                 imageMemoryTypeIndexFound = true;
245                 break;
246             }
247         }
248 
249         if (!imageMemoryTypeIndexFound) {
250             VK_ANB_ERR(
251                 "VK_ANDROID_native_buffer: could not obtain "
252                 "image memory type index");
253             teardownAndroidNativeBufferImage(vk, out);
254             return VK_ERROR_OUT_OF_DEVICE_MEMORY;
255         }
256 
257         out->imageMemoryTypeIndex = imageMemoryTypeIndex;
258 
259         VkMemoryAllocateInfo allocInfo = {
260             VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
261             0,
262             out->memReqs.size,
263             out->imageMemoryTypeIndex,
264         };
265 
266         if (VK_SUCCESS != vk->vkAllocateMemory(device, &allocInfo, nullptr, &out->imageMemory)) {
267             VK_ANB_ERR(
268                 "VK_ANDROID_native_buffer: could not allocate "
269                 "image memory. requested size: %zu",
270                 (size_t)(out->memReqs.size));
271             teardownAndroidNativeBufferImage(vk, out);
272             return VK_ERROR_OUT_OF_DEVICE_MEMORY;
273         }
274     }
275 
276     if (VK_SUCCESS != vk->vkBindImageMemory(device, out->image, out->imageMemory, bindOffset)) {
277         VK_ANB_ERR(
278             "VK_ANDROID_native_buffer: could not bind "
279             "image memory.");
280         teardownAndroidNativeBufferImage(vk, out);
281         return VK_ERROR_OUT_OF_DEVICE_MEMORY;
282     }
283 
284     // Allocate a staging memory and set up the staging buffer.
285     // TODO: Make this shared as well if we can get that to
286     // work on Windows with NVIDIA.
287     {
288         VkBufferCreateInfo stagingBufferCreateInfo = {
289             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
290             0,
291             0,
292             out->memReqs.size,
293             VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
294             VK_SHARING_MODE_EXCLUSIVE,
295             0,
296             nullptr,
297         };
298         if (out->queueFamilyIndices.size() > 1) {
299             stagingBufferCreateInfo.sharingMode = VK_SHARING_MODE_CONCURRENT;
300             stagingBufferCreateInfo.queueFamilyIndexCount =
301                 static_cast<uint32_t>(out->queueFamilyIndices.size());
302             stagingBufferCreateInfo.pQueueFamilyIndices = out->queueFamilyIndices.data();
303         }
304 
305         if (VK_SUCCESS !=
306             vk->vkCreateBuffer(device, &stagingBufferCreateInfo, nullptr, &out->stagingBuffer)) {
307             VK_ANB_ERR(
308                 "VK_ANDROID_native_buffer: could not create "
309                 "staging buffer.");
310             teardownAndroidNativeBufferImage(vk, out);
311             return VK_ERROR_OUT_OF_HOST_MEMORY;
312         }
313 
314         VkMemoryRequirements stagingMemReqs;
315         vk->vkGetBufferMemoryRequirements(device, out->stagingBuffer, &stagingMemReqs);
316         if (stagingMemReqs.size < out->memReqs.size) {
317             VK_ANB_ERR(
318                 "VK_ANDROID_native_buffer: unexpected staging buffer size");
319             teardownAndroidNativeBufferImage(vk, out);
320             return VK_ERROR_OUT_OF_HOST_MEMORY;
321         }
322 
323         bool stagingIndexRes =
324             getStagingMemoryTypeIndex(vk, device, memProps, &out->stagingMemoryTypeIndex);
325 
326         if (!stagingIndexRes) {
327             VK_ANB_ERR(
328                 "VK_ANDROID_native_buffer: could not obtain "
329                 "staging memory type index");
330             teardownAndroidNativeBufferImage(vk, out);
331             return VK_ERROR_OUT_OF_HOST_MEMORY;
332         }
333 
334         VkMemoryAllocateInfo allocInfo = {
335             VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
336             0,
337             stagingMemReqs.size,
338             out->stagingMemoryTypeIndex,
339         };
340 
341         VkResult res = vk->vkAllocateMemory(device, &allocInfo, nullptr, &out->stagingMemory);
342         if (VK_SUCCESS != res) {
343             VK_ANB_ERR(
344                 "VK_ANDROID_native_buffer: could not allocate staging memory. "
345                 "res = %d. requested size: %zu",
346                 (int)res, (size_t)(out->memReqs.size));
347             teardownAndroidNativeBufferImage(vk, out);
348             return VK_ERROR_OUT_OF_HOST_MEMORY;
349         }
350 
351         if (VK_SUCCESS !=
352             vk->vkBindBufferMemory(device, out->stagingBuffer, out->stagingMemory, 0)) {
353             VK_ANB_ERR(
354                 "VK_ANDROID_native_buffer: could not bind "
355                 "staging buffer to staging memory.");
356             teardownAndroidNativeBufferImage(vk, out);
357             return VK_ERROR_OUT_OF_HOST_MEMORY;
358         }
359 
360         if (VK_SUCCESS != vk->vkMapMemory(device, out->stagingMemory, 0, VK_WHOLE_SIZE, 0,
361                                           (void**)&out->mappedStagingPtr)) {
362             VK_ANB_ERR(
363                 "VK_ANDROID_native_buffer: could not map "
364                 "staging buffer.");
365             teardownAndroidNativeBufferImage(vk, out);
366             return VK_ERROR_OUT_OF_HOST_MEMORY;
367         }
368     }
369 
370     out->qsriWaitFencePool =
371         std::make_unique<AndroidNativeBufferInfo::QsriWaitFencePool>(out->vk, out->device);
372     out->qsriTimeline = std::make_unique<VkQsriTimeline>();
373     return VK_SUCCESS;
374 }
375 
teardownAndroidNativeBufferImage(VulkanDispatch * vk,AndroidNativeBufferInfo * anbInfo)376 void teardownAndroidNativeBufferImage(VulkanDispatch* vk, AndroidNativeBufferInfo* anbInfo) {
377     auto device = anbInfo->device;
378 
379     auto image = anbInfo->image;
380     auto imageMemory = anbInfo->imageMemory;
381 
382     auto stagingBuffer = anbInfo->stagingBuffer;
383     auto mappedPtr = anbInfo->mappedStagingPtr;
384     auto stagingMemory = anbInfo->stagingMemory;
385 
386     for (auto queueState : anbInfo->queueStates) {
387         queueState.teardown(vk, device);
388     }
389 
390     anbInfo->queueStates.clear();
391 
392     anbInfo->acquireQueueState.teardown(vk, device);
393 
394     if (image) vk->vkDestroyImage(device, image, nullptr);
395     if (imageMemory) vk->vkFreeMemory(device, imageMemory, nullptr);
396     if (stagingBuffer) vk->vkDestroyBuffer(device, stagingBuffer, nullptr);
397     if (mappedPtr) vk->vkUnmapMemory(device, stagingMemory);
398     if (stagingMemory) vk->vkFreeMemory(device, stagingMemory, nullptr);
399 
400     anbInfo->vk = nullptr;
401     anbInfo->device = VK_NULL_HANDLE;
402     anbInfo->image = VK_NULL_HANDLE;
403     anbInfo->imageMemory = VK_NULL_HANDLE;
404     anbInfo->stagingBuffer = VK_NULL_HANDLE;
405     anbInfo->mappedStagingPtr = nullptr;
406     anbInfo->stagingMemory = VK_NULL_HANDLE;
407 
408     anbInfo->qsriWaitFencePool = nullptr;
409 }
410 
getGralloc0Usage(VkFormat format,VkImageUsageFlags imageUsage,int * usage_out)411 void getGralloc0Usage(VkFormat format, VkImageUsageFlags imageUsage, int* usage_out) {
412     // Pick some default flexible values for gralloc usage for now.
413     (void)format;
414     (void)imageUsage;
415     *usage_out = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
416                  GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
417 }
418 
419 // Taken from Android GrallocUsageConversion.h
getGralloc1Usage(VkFormat format,VkImageUsageFlags imageUsage,VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,uint64_t * consumerUsage_out,uint64_t * producerUsage_out)420 void getGralloc1Usage(VkFormat format, VkImageUsageFlags imageUsage,
421                       VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
422                       uint64_t* consumerUsage_out, uint64_t* producerUsage_out) {
423     // Pick some default flexible values for gralloc usage for now.
424     (void)format;
425     (void)imageUsage;
426     (void)swapchainImageUsage;
427 
428     constexpr int usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
429                           GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
430 
431     constexpr uint64_t PRODUCER_MASK =
432         GRALLOC1_PRODUCER_USAGE_CPU_READ |
433         /* GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN | */
434         GRALLOC1_PRODUCER_USAGE_CPU_WRITE |
435         /* GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN | */
436         GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET | GRALLOC1_PRODUCER_USAGE_PROTECTED |
437         GRALLOC1_PRODUCER_USAGE_CAMERA | GRALLOC1_PRODUCER_USAGE_VIDEO_DECODER |
438         GRALLOC1_PRODUCER_USAGE_SENSOR_DIRECT_DATA;
439     constexpr uint64_t CONSUMER_MASK =
440         GRALLOC1_CONSUMER_USAGE_CPU_READ |
441         /* GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN | */
442         GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE | GRALLOC1_CONSUMER_USAGE_HWCOMPOSER |
443         GRALLOC1_CONSUMER_USAGE_CLIENT_TARGET | GRALLOC1_CONSUMER_USAGE_CURSOR |
444         GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER | GRALLOC1_CONSUMER_USAGE_CAMERA |
445         GRALLOC1_CONSUMER_USAGE_RENDERSCRIPT | GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
446 
447     *producerUsage_out = static_cast<uint64_t>(usage) & PRODUCER_MASK;
448     *consumerUsage_out = static_cast<uint64_t>(usage) & CONSUMER_MASK;
449 
450     if ((static_cast<uint32_t>(usage) & GRALLOC_USAGE_SW_READ_OFTEN) ==
451         GRALLOC_USAGE_SW_READ_OFTEN) {
452         *producerUsage_out |= GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN;
453         *consumerUsage_out |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
454     }
455 
456     if ((static_cast<uint32_t>(usage) & GRALLOC_USAGE_SW_WRITE_OFTEN) ==
457         GRALLOC_USAGE_SW_WRITE_OFTEN) {
458         *producerUsage_out |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
459     }
460 }
461 
setup(VulkanDispatch * vk,VkDevice device,VkQueue queueIn,uint32_t queueFamilyIndexIn,android::base::Lock * queueLockIn)462 void AndroidNativeBufferInfo::QueueState::setup(VulkanDispatch* vk, VkDevice device,
463                                                 VkQueue queueIn, uint32_t queueFamilyIndexIn,
464                                                 android::base::Lock* queueLockIn) {
465     queue = queueIn;
466     queueFamilyIndex = queueFamilyIndexIn;
467     lock = queueLockIn;
468 
469     VkCommandPoolCreateInfo poolCreateInfo = {
470         VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
471         0,
472         VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
473         queueFamilyIndex,
474     };
475 
476     vk->vkCreateCommandPool(device, &poolCreateInfo, nullptr, &pool);
477 
478     VkCommandBufferAllocateInfo cbAllocInfo = {
479         VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1,
480     };
481 
482     vk->vkAllocateCommandBuffers(device, &cbAllocInfo, &cb);
483 
484     vk->vkAllocateCommandBuffers(device, &cbAllocInfo, &cb2);
485 
486     VkFenceCreateInfo fenceCreateInfo = {
487         VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
488         0,
489         0,
490     };
491 
492     vk->vkCreateFence(device, &fenceCreateInfo, nullptr, &fence);
493 }
494 
teardown(VulkanDispatch * vk,VkDevice device)495 void AndroidNativeBufferInfo::QueueState::teardown(VulkanDispatch* vk, VkDevice device) {
496     if (latestUse) {
497         latestUse->wait();
498     }
499 
500     if (queue) {
501         AutoLock qlock(*lock);
502         vk->vkQueueWaitIdle(queue);
503     }
504     if (cb) vk->vkFreeCommandBuffers(device, pool, 1, &cb);
505     if (pool) vk->vkDestroyCommandPool(device, pool, nullptr);
506     if (fence) vk->vkDestroyFence(device, fence, nullptr);
507 
508     lock = nullptr;
509     queue = VK_NULL_HANDLE;
510     pool = VK_NULL_HANDLE;
511     cb = VK_NULL_HANDLE;
512     fence = VK_NULL_HANDLE;
513     queueFamilyIndex = 0;
514 }
515 
setAndroidNativeImageSemaphoreSignaled(VulkanDispatch * vk,VkDevice device,VkQueue defaultQueue,uint32_t defaultQueueFamilyIndex,Lock * defaultQueueLock,VkSemaphore semaphore,VkFence fence,AndroidNativeBufferInfo * anbInfo)516 VkResult setAndroidNativeImageSemaphoreSignaled(VulkanDispatch* vk, VkDevice device,
517                                                 VkQueue defaultQueue,
518                                                 uint32_t defaultQueueFamilyIndex,
519                                                 Lock* defaultQueueLock, VkSemaphore semaphore,
520                                                 VkFence fence, AndroidNativeBufferInfo* anbInfo) {
521     auto emu = getGlobalVkEmulation();
522 
523     bool firstTimeSetup = !anbInfo->everSynced && !anbInfo->everAcquired;
524 
525     anbInfo->everAcquired = true;
526 
527     if (firstTimeSetup) {
528         VkSubmitInfo submitInfo = {
529             VK_STRUCTURE_TYPE_SUBMIT_INFO,
530             0,
531             0,
532             nullptr,
533             nullptr,
534             0,
535             nullptr,
536             (uint32_t)(semaphore == VK_NULL_HANDLE ? 0 : 1),
537             semaphore == VK_NULL_HANDLE ? nullptr : &semaphore,
538         };
539         AutoLock qlock(*defaultQueueLock);
540         VK_CHECK(vk->vkQueueSubmit(defaultQueue, 1, &submitInfo, fence));
541     } else {
542         // Setup queue state for this queue family index.
543         auto queueFamilyIndex = anbInfo->lastUsedQueueFamilyIndex;
544         if (queueFamilyIndex >= anbInfo->queueStates.size()) {
545             anbInfo->queueStates.resize(queueFamilyIndex + 1);
546         }
547         AndroidNativeBufferInfo::QueueState& queueState =
548             anbInfo->queueStates[queueFamilyIndex];
549         if (!queueState.queue) {
550             queueState.setup(vk, anbInfo->device, defaultQueue, queueFamilyIndex, defaultQueueLock);
551         }
552 
553         // If we used the Vulkan image without copying it back
554         // to the CPU, reset the layout to PRESENT.
555         if (anbInfo->useVulkanNativeImage) {
556             VkCommandBufferBeginInfo beginInfo = {
557                 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
558                 0,
559                 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
560                 nullptr /* no inheritance info */,
561             };
562 
563             vk->vkBeginCommandBuffer(queueState.cb2, &beginInfo);
564 
565             emu->debugUtilsHelper.cmdBeginDebugLabel(queueState.cb2,
566                                                      "vkAcquireImageANDROID(ColorBuffer:%d)",
567                                                      anbInfo->colorBufferHandle);
568 
569             VkImageMemoryBarrier queueTransferBarrier = {
570                 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
571                 .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
572                 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
573                 .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
574                 .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
575                 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
576                 .dstQueueFamilyIndex = anbInfo->lastUsedQueueFamilyIndex,
577                 .image = anbInfo->image,
578                 .subresourceRange =
579                     {
580                         VK_IMAGE_ASPECT_COLOR_BIT,
581                         0,
582                         1,
583                         0,
584                         1,
585                     },
586             };
587             vk->vkCmdPipelineBarrier(queueState.cb2, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
588                                      VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr,
589                                      1, &queueTransferBarrier);
590 
591             emu->debugUtilsHelper.cmdEndDebugLabel(queueState.cb2);
592 
593             vk->vkEndCommandBuffer(queueState.cb2);
594 
595             VkSubmitInfo submitInfo = {
596                 VK_STRUCTURE_TYPE_SUBMIT_INFO,
597                 0,
598                 0,
599                 nullptr,
600                 nullptr,
601                 1,
602                 &queueState.cb2,
603                 (uint32_t)(semaphore == VK_NULL_HANDLE ? 0 : 1),
604                 semaphore == VK_NULL_HANDLE ? nullptr : &semaphore,
605             };
606 
607             AutoLock qlock(*queueState.lock);
608             // TODO(kaiyili): initiate ownership transfer from DisplayVk here
609             VK_CHECK(vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, fence));
610         } else {
611             const AndroidNativeBufferInfo::QueueState& queueState =
612                 anbInfo->queueStates[anbInfo->lastUsedQueueFamilyIndex];
613             VkSubmitInfo submitInfo = {
614                 VK_STRUCTURE_TYPE_SUBMIT_INFO,
615                 0,
616                 0,
617                 nullptr,
618                 nullptr,
619                 0,
620                 nullptr,
621                 (uint32_t)(semaphore == VK_NULL_HANDLE ? 0 : 1),
622                 semaphore == VK_NULL_HANDLE ? nullptr : &semaphore,
623             };
624             AutoLock qlock(*queueState.lock);
625             VK_CHECK(vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, fence));
626         }
627     }
628 
629     return VK_SUCCESS;
630 }
631 
632 static constexpr uint64_t kTimeoutNs = 3ULL * 1000000000ULL;
633 
syncImageToColorBuffer(gfxstream::host::BackendCallbacks & callbacks,VulkanDispatch * vk,uint32_t queueFamilyIndex,VkQueue queue,Lock * queueLock,uint32_t waitSemaphoreCount,const VkSemaphore * pWaitSemaphores,int * pNativeFenceFd,AndroidNativeBufferInfo * anbInfo)634 VkResult syncImageToColorBuffer(gfxstream::host::BackendCallbacks& callbacks, VulkanDispatch* vk,
635                                 uint32_t queueFamilyIndex, VkQueue queue, Lock* queueLock,
636                                 uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores,
637                                 int* pNativeFenceFd, AndroidNativeBufferInfo* anbInfo) {
638     const uint64_t traceId = gfxstream::host::GetUniqueTracingId();
639     GFXSTREAM_TRACE_EVENT(GFXSTREAM_TRACE_DEFAULT_CATEGORY, "vkQSRI syncImageToColorBuffer()",
640                           GFXSTREAM_TRACE_FLOW(traceId));
641 
642     auto fb = FrameBuffer::getFB();
643     fb->lock();
644 
645     // Implicitly synchronized
646     *pNativeFenceFd = -1;
647 
648     anbInfo->everSynced = true;
649     anbInfo->lastUsedQueueFamilyIndex = queueFamilyIndex;
650 
651     // Setup queue state for this queue family index.
652     if (queueFamilyIndex >= anbInfo->queueStates.size()) {
653         anbInfo->queueStates.resize(queueFamilyIndex + 1);
654     }
655 
656     auto& queueState = anbInfo->queueStates[queueFamilyIndex];
657 
658     if (!queueState.queue) {
659         queueState.setup(vk, anbInfo->device, queue, queueFamilyIndex, queueLock);
660     }
661 
662     auto emu = getGlobalVkEmulation();
663 
664     // Record our synchronization commands.
665     VkCommandBufferBeginInfo beginInfo = {
666         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
667         0,
668         VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
669         nullptr /* no inheritance info */,
670     };
671 
672     vk->vkBeginCommandBuffer(queueState.cb, &beginInfo);
673 
674     emu->debugUtilsHelper.cmdBeginDebugLabel(queueState.cb,
675                                              "vkQueueSignalReleaseImageANDROID(ColorBuffer:%d)",
676                                              anbInfo->colorBufferHandle);
677 
678     // If using the Vulkan image directly (rather than copying it back to
679     // the CPU), change its layout for that use.
680     if (anbInfo->useVulkanNativeImage) {
681         VkImageMemoryBarrier queueTransferBarrier = {
682             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
683             .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
684             .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
685             .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
686             .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
687             .srcQueueFamilyIndex = queueFamilyIndex,
688             .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
689             .image = anbInfo->image,
690             .subresourceRange =
691                 {
692                     VK_IMAGE_ASPECT_COLOR_BIT,
693                     0,
694                     1,
695                     0,
696                     1,
697                 },
698         };
699         vk->vkCmdPipelineBarrier(queueState.cb, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
700                                  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
701                                  &queueTransferBarrier);
702 
703     } else {
704         // Not a GL texture. Read it back and put it back in present layout.
705 
706         // From the spec: If an application does not need the contents of a resource
707         // to remain valid when transferring from one queue family to another, then
708         // the ownership transfer should be skipped.
709         // We definitely need to transition the image to
710         // VK_TRANSFER_SRC_OPTIMAL and back.
711         VkImageMemoryBarrier presentToTransferSrc = {
712             VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
713             0,
714             0,
715             VK_ACCESS_TRANSFER_READ_BIT,
716             VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
717             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
718             VK_QUEUE_FAMILY_IGNORED,
719             VK_QUEUE_FAMILY_IGNORED,
720             anbInfo->image,
721             {
722                 VK_IMAGE_ASPECT_COLOR_BIT,
723                 0,
724                 1,
725                 0,
726                 1,
727             },
728         };
729 
730         vk->vkCmdPipelineBarrier(queueState.cb, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
731                                  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
732                                  &presentToTransferSrc);
733 
734         VkBufferImageCopy region = {
735             0 /* buffer offset */,
736             anbInfo->extent.width,
737             anbInfo->extent.height,
738             {
739                 VK_IMAGE_ASPECT_COLOR_BIT,
740                 0,
741                 0,
742                 1,
743             },
744             {0, 0, 0},
745             anbInfo->extent,
746         };
747 
748         vk->vkCmdCopyImageToBuffer(queueState.cb, anbInfo->image,
749                                    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, anbInfo->stagingBuffer, 1,
750                                    &region);
751 
752         // Transfer back to present src.
753         VkImageMemoryBarrier backToPresentSrc = {
754             VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
755             0,
756             VK_ACCESS_TRANSFER_READ_BIT,
757             0,
758             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
759             VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
760             VK_QUEUE_FAMILY_IGNORED,
761             VK_QUEUE_FAMILY_IGNORED,
762             anbInfo->image,
763             {
764                 VK_IMAGE_ASPECT_COLOR_BIT,
765                 0,
766                 1,
767                 0,
768                 1,
769             },
770         };
771 
772         vk->vkCmdPipelineBarrier(queueState.cb, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
773                                  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
774                                  &backToPresentSrc);
775     }
776 
777     emu->debugUtilsHelper.cmdEndDebugLabel(queueState.cb);
778 
779     vk->vkEndCommandBuffer(queueState.cb);
780 
781     std::vector<VkPipelineStageFlags> pipelineStageFlags;
782     pipelineStageFlags.resize(waitSemaphoreCount, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
783 
784     VkSubmitInfo submitInfo = {
785         VK_STRUCTURE_TYPE_SUBMIT_INFO,
786         0,
787         waitSemaphoreCount,
788         pWaitSemaphores,
789         pipelineStageFlags.data(),
790         1,
791         &queueState.cb,
792         0,
793         nullptr,
794     };
795 
796     // TODO(kaiyili): initiate ownership transfer to DisplayVk here.
797     VkFence qsriFence = anbInfo->qsriWaitFencePool->getFenceFromPool();
798     AutoLock qLock(*queueLock);
799     VK_CHECK(vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, qsriFence));
800     auto waitForQsriFenceTask = [anbInfo, vk, device = anbInfo->device, qsriFence, traceId] {
801         GFXSTREAM_TRACE_EVENT(GFXSTREAM_TRACE_DEFAULT_CATEGORY, "Wait for QSRI fence",
802                               GFXSTREAM_TRACE_FLOW(traceId));
803 
804         VK_ANB_DEBUG_OBJ(anbInfo, "wait callback: enter");
805         VK_ANB_DEBUG_OBJ(anbInfo, "wait callback: wait for fence %p...", qsriFence);
806         VkResult res = vk->vkWaitForFences(device, 1, &qsriFence, VK_FALSE, kTimeoutNs);
807         switch (res) {
808             case VK_SUCCESS:
809                 break;
810             case VK_TIMEOUT:
811                 VK_ANB_ERR("Timeout when waiting for the Qsri fence.");
812                 break;
813             default:
814                 ERR("Failed to wait for QSRI fence: %s\n", string_VkResult(res));
815                 VK_CHECK(res);
816         }
817         VK_ANB_DEBUG_OBJ(anbInfo, "wait callback: wait for fence %p...(done)", qsriFence);
818         anbInfo->qsriWaitFencePool->returnFence(qsriFence);
819     };
820     fb->unlock();
821 
822     if (anbInfo->useVulkanNativeImage) {
823         VK_ANB_DEBUG_OBJ(anbInfo, "using native image, so use sync thread to wait");
824         // Queue wait to sync thread with completion callback
825         // Pass anbInfo by value to get a ref
826         auto waitable = callbacks.scheduleAsyncWork(
827             [waitForQsriFenceTask = std::move(waitForQsriFenceTask), anbInfo]() mutable {
828                 waitForQsriFenceTask();
829                 anbInfo->qsriTimeline->signalNextPresentAndPoll();
830             },
831             "wait for the guest Qsri VkFence signaled");
832 
833         queueState.latestUse = std::move(waitable);
834     } else {
835         VK_ANB_DEBUG_OBJ(anbInfo, "not using native image, so wait right away");
836         waitForQsriFenceTask();
837 
838         VkMappedMemoryRange toInvalidate = {
839             VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, anbInfo->stagingMemory, 0, VK_WHOLE_SIZE,
840         };
841 
842         vk->vkInvalidateMappedMemoryRanges(anbInfo->device, 1, &toInvalidate);
843 
844         uint32_t colorBufferHandle = anbInfo->colorBufferHandle;
845 
846         // Copy to from staging buffer to color buffer
847         uint32_t bpp = 4; /* format always rgba8...not */
848         switch (anbInfo->vkFormat) {
849             case VK_FORMAT_R5G6B5_UNORM_PACK16:
850                 bpp = 2;
851                 break;
852             case VK_FORMAT_R8G8B8_UNORM:
853                 bpp = 3;
854                 break;
855             default:
856             case VK_FORMAT_R8G8B8A8_UNORM:
857             case VK_FORMAT_B8G8R8A8_UNORM:
858                 bpp = 4;
859                 break;
860         }
861         const void* bytes = anbInfo->mappedStagingPtr;
862         const size_t bytesSize = bpp * anbInfo->extent.width * anbInfo->extent.height;
863         callbacks.flushColorBufferFromBytes(colorBufferHandle, bytes, bytesSize);
864 
865         anbInfo->qsriTimeline->signalNextPresentAndPoll();
866     }
867 
868     return VK_SUCCESS;
869 }
870 
871 }  // namespace vk
872 }  // namespace gfxstream
873