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