diff options
author | Lingfeng Yang <lfy@google.com> | 2021-07-15 16:50:37 -0700 |
---|---|---|
committer | Lingfeng Yang <lfy@google.com> | 2021-07-21 13:51:54 -0700 |
commit | 9e750257b11b42bf7a49059db8533c935d3cc2db (patch) | |
tree | 8179a6d305432e3d07b9960a22ed3ef84ad085ef /stream-servers/vulkan | |
parent | af686801c2caaade06e2adeccae04fa77043b4d9 (diff) | |
download | vulkan-cereal-9e750257b11b42bf7a49059db8533c935d3cc2db.tar.gz |
vulkan: wait sync fd for vkQSRI
Bug: 193809913
This CL adds the async vkQSRI functionality, and enables the feature
flag (if fence contexts are available).
Change-Id: I5e67167618b318a74bfb55528951ca95007df614
Diffstat (limited to 'stream-servers/vulkan')
-rw-r--r-- | stream-servers/vulkan/VkAndroidNativeBuffer.cpp | 120 | ||||
-rw-r--r-- | stream-servers/vulkan/VkAndroidNativeBuffer.h | 60 | ||||
-rw-r--r-- | stream-servers/vulkan/VkDecoderGlobalState.cpp | 82 | ||||
-rw-r--r-- | stream-servers/vulkan/VkDecoderGlobalState.h | 7 |
4 files changed, 246 insertions, 23 deletions
diff --git a/stream-servers/vulkan/VkAndroidNativeBuffer.cpp b/stream-servers/vulkan/VkAndroidNativeBuffer.cpp index 7cbfb5a2..a47bb4d0 100644 --- a/stream-servers/vulkan/VkAndroidNativeBuffer.cpp +++ b/stream-servers/vulkan/VkAndroidNativeBuffer.cpp @@ -19,13 +19,61 @@ #include "GrallocDefs.h" #include "VkCommonOperations.h" #include "VulkanDispatch.h" +#include "SyncThread.h" #include <string.h> #define VK_ANB_ERR(fmt,...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); +#define VK_ANB_DEBUG 0 + +#if VK_ANB_DEBUG +#define VK_ANB_DEBUG(fmt,...) fprintf(stderr, "vk-anb-debug: %s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); +#define VK_ANB_DEBUG_OBJ(obj, fmt,...) fprintf(stderr, "vk-anb-debug: %s:%d:%p " fmt "\n", __func__, __LINE__, obj, ##__VA_ARGS__); +#else +#define VK_ANB_DEBUG(fmt,...) +#define VK_ANB_DEBUG_OBJ(obj, fmt,...) +#endif + +using android::base::AutoLock; +using android::base::Lock; + namespace goldfish_vk { +VkFence AndroidNativeBufferInfo::QsriWaitInfo::getFenceFromPoolLocked() { + VK_ANB_DEBUG("enter"); + + if (!vk) return VK_NULL_HANDLE; + + if (fencePool.empty()) { + VkFence fence; + VkFenceCreateInfo fenceCreateInfo = { + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 0, 0, + }; + vk->vkCreateFence(device, &fenceCreateInfo, nullptr, &fence); + VK_ANB_DEBUG("no fences in pool, created %p", fence); + return fence; + } else { + VkFence res = fencePool.back(); + fencePool.pop_back(); + vk->vkResetFences(device, 1, &res); + VK_ANB_DEBUG("existing fence in pool: %p. also reset the fence", res); + return res; + } +} + +AndroidNativeBufferInfo::QsriWaitInfo::~QsriWaitInfo() { + VK_ANB_DEBUG("enter"); + if (!vk) return; + if (!device) return; + // Nothing in the fence pool is unsignaled + for (auto fence : fencePool) { + VK_ANB_DEBUG("destroy fence %p", fence); + vk->vkDestroyFence(device, fence, nullptr); + } + VK_ANB_DEBUG("exit"); +} + bool parseAndroidNativeBufferInfo( const VkImageCreateInfo* pCreateInfo, AndroidNativeBufferInfo* info_out) { @@ -48,8 +96,7 @@ VkResult prepareAndroidNativeBufferImage( const VkPhysicalDeviceMemoryProperties* memProps, AndroidNativeBufferInfo* out) { - *out = {}; - + out->vk = vk; out->device = device; out->vkFormat = pCreateInfo->format; out->extent = pCreateInfo->extent; @@ -273,11 +320,22 @@ void teardownAndroidNativeBufferImage( for (auto queueState : anbInfo->queueStates) { queueState.teardown(vk, device); } + anbInfo->queueStates.clear(); anbInfo->acquireQueueState.teardown(vk, device); - *anbInfo = {}; + anbInfo->vk = nullptr; + anbInfo->device = VK_NULL_HANDLE; + anbInfo->image = VK_NULL_HANDLE; + anbInfo->imageMemory = VK_NULL_HANDLE; + anbInfo->stagingBuffer = VK_NULL_HANDLE; + anbInfo->mappedStagingPtr = nullptr; + anbInfo->stagingMemory = VK_NULL_HANDLE; + + AutoLock lock(anbInfo->qsriWaitInfo.lock); + anbInfo->qsriWaitInfo.presentCount = 0; + anbInfo->qsriWaitInfo.requestedPresentCount = 0; } void getGralloc0Usage(VkFormat format, VkImageUsageFlags imageUsage, @@ -505,6 +563,8 @@ VkResult setAndroidNativeImageSemaphoreSignaled( return VK_SUCCESS; } +static constexpr uint64_t kTimeoutNs = 3ULL * 1000000000ULL; + VkResult syncImageToColorBuffer( VulkanDispatch* vk, uint32_t queueFamilyIndex, @@ -512,7 +572,14 @@ VkResult syncImageToColorBuffer( uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, int* pNativeFenceFd, - AndroidNativeBufferInfo* anbInfo) { + std::shared_ptr<AndroidNativeBufferInfo> anbInfo) { + + auto anbInfoPtr = anbInfo.get(); + { + AutoLock lock(anbInfo->qsriWaitInfo.lock); + VK_ANB_DEBUG_OBJ(anbInfoPtr, "ensure dispatch %p device %p", vk, anbInfo->device); + anbInfo->qsriWaitInfo.ensureDispatchAndDevice(vk, anbInfo->device); + } auto fb = FrameBuffer::getFB(); fb->lock(); @@ -662,13 +729,46 @@ VkResult syncImageToColorBuffer( }; // TODO(kaiyili): initiate ownership transfer to DisplayVk here. - vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, VK_NULL_HANDLE); - + VkFence qsriFence = VK_NULL_HANDLE; + { + VK_ANB_DEBUG_OBJ(anbInfoPtr, "trying to get qsri fence"); + AutoLock lock(anbInfo->qsriWaitInfo.lock); + VK_ANB_DEBUG_OBJ(anbInfoPtr, "trying to get qsri fence (got lock)"); + qsriFence = anbInfo->qsriWaitInfo.getFenceFromPoolLocked(); + VK_ANB_DEBUG_OBJ(anbInfoPtr, "got qsri fence %p", qsriFence); + } + vk->vkQueueSubmit(queueState.queue, 1, &submitInfo, qsriFence); fb->unlock(); if (anbInfo->useVulkanNativeImage) { + VK_ANB_DEBUG_OBJ(anbInfoPtr, "using native image, so use sync thread to wait"); fb->setColorBufferInUse(anbInfo->colorBufferHandle, false); + VkDevice device = anbInfo->device; + // Queue wait to sync thread with completion callback + // Pass anbInfo by value to get a ref + SyncThread::get()->triggerGeneral([anbInfoPtr, anbInfo, vk, device, qsriFence] { + VK_ANB_DEBUG_OBJ(anbInfoPtr, "wait callback: enter"); + if (qsriFence) { + VK_ANB_DEBUG_OBJ(anbInfoPtr, "wait callback: wait for fence %p...", qsriFence); + vk->vkWaitForFences(device, 1, &qsriFence, VK_FALSE, kTimeoutNs); + VK_ANB_DEBUG_OBJ(anbInfoPtr, "wait callback: wait for fence %p...(done)", qsriFence); + } + AutoLock lock(anbInfo->qsriWaitInfo.lock); + VK_ANB_DEBUG_OBJ(anbInfoPtr, "wait callback: return fence and signal"); + if (qsriFence) { + anbInfo->qsriWaitInfo.returnFenceLocked(qsriFence); + } + ++anbInfo->qsriWaitInfo.presentCount; + VK_ANB_DEBUG_OBJ(anbInfoPtr, "wait callback: done, present count is now %llu", (unsigned long long)anbInfo->qsriWaitInfo.presentCount); + anbInfo->qsriWaitInfo.cv.signal(); + VK_ANB_DEBUG_OBJ(anbInfoPtr, "wait callback: exit"); + }); } else { + VK_ANB_DEBUG_OBJ(anbInfoPtr, "not using native image, so wait right away"); + if (qsriFence) { + vk->vkWaitForFences(anbInfo->device, 1, &qsriFence, VK_FALSE, kTimeoutNs); + } + VkMappedMemoryRange toInvalidate = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, anbInfo->stagingMemory, @@ -701,6 +801,14 @@ VkResult syncImageToColorBuffer( colorBufferHandle, anbInfo->mappedStagingPtr, bpp * anbInfo->extent.width * anbInfo->extent.height); + + AutoLock lock(anbInfo->qsriWaitInfo.lock); + ++anbInfo->qsriWaitInfo.presentCount; + VK_ANB_DEBUG_OBJ(anbInfoPtr, "done, present count is now %llu", (unsigned long long)anbInfo->qsriWaitInfo.presentCount); + anbInfo->qsriWaitInfo.cv.signal(); + if (qsriFence) { + anbInfo->qsriWaitInfo.returnFenceLocked(qsriFence); + } } return VK_SUCCESS; diff --git a/stream-servers/vulkan/VkAndroidNativeBuffer.h b/stream-servers/vulkan/VkAndroidNativeBuffer.h index 4feed9c0..72e84b60 100644 --- a/stream-servers/vulkan/VkAndroidNativeBuffer.h +++ b/stream-servers/vulkan/VkAndroidNativeBuffer.h @@ -17,12 +17,17 @@ #include <vulkan/vulkan.h> +#include "base/Lock.h" +#include "base/ConditionVariable.h" #include "cereal/common/goldfish_vk_private_defs.h" +#include <deque> +#include <memory> #include <vector> namespace goldfish_vk { +struct AndroidNativeBufferInfo; struct VulkanDispatch; // This class provides methods to create and query information about Android @@ -32,7 +37,18 @@ struct VulkanDispatch; // This is to be refactored to move to external memory only once we get that // working. +void teardownAndroidNativeBufferImage( + VulkanDispatch* vk, + AndroidNativeBufferInfo* anbInfo); + struct AndroidNativeBufferInfo { + ~AndroidNativeBufferInfo() { + if (vk) { + teardownAndroidNativeBufferImage(vk, this); + } + } + + VulkanDispatch* vk = nullptr; VkDevice device = VK_NULL_HANDLE; VkFormat vkFormat; VkExtent3D extent; @@ -87,6 +103,7 @@ struct AndroidNativeBufferInfo { // We keep one QueueState for each queue family index used by the guest // in vkQueuePresentKHR. std::vector<QueueState> queueStates; + // Did we ever sync the Vulkan image with a ColorBuffer? // If so, set everSynced along with the queue family index // used to do that. @@ -101,6 +118,43 @@ struct AndroidNativeBufferInfo { // Track that here. bool everAcquired = false; QueueState acquireQueueState; + + // State that is of interest when interacting with sync fds and SyncThread. + // Protected by this lock and condition variable. + struct QsriWaitInfo { + android::base::Lock lock; + android::base::ConditionVariable cv; + + VulkanDispatch* vk = nullptr; + VkDevice device = VK_NULL_HANDLE; + + // A pool of vkFences for waiting (optimization so we don't keep recreating them every time). + std::vector<VkFence> fencePool; + + // How many times the image was presented via vkQueueSignalReleaseImageANDROID + // versus how many times we want it to be (for sync fd fence waiting). + // Incremented by waitQsri. + uint64_t requestedPresentCount = 0; + // Incremented by waitQsri if vkWaitForFences there succeeds, + // or by syncImageToColorBuffer in the non-zero-copy case. + uint64_t presentCount = 0; + + void ensureDispatchAndDevice(VulkanDispatch* vkIn, VkDevice deviceIn) { + vk = vkIn; + device = deviceIn; + } + + VkFence getFenceFromPoolLocked(); + + // requires fence to be signaled + void returnFenceLocked(VkFence fence) { + fencePool.push_back(fence); + } + + ~QsriWaitInfo(); + }; + + QsriWaitInfo qsriWaitInfo; }; VkResult prepareAndroidNativeBufferImage( @@ -112,10 +166,6 @@ VkResult prepareAndroidNativeBufferImage( const VkPhysicalDeviceMemoryProperties* memProps, AndroidNativeBufferInfo* out); -void teardownAndroidNativeBufferImage( - VulkanDispatch* vk, - AndroidNativeBufferInfo* anbInfo); - void getGralloc0Usage(VkFormat format, VkImageUsageFlags imageUsage, int* usage_out); void getGralloc1Usage(VkFormat format, VkImageUsageFlags imageUsage, @@ -139,6 +189,6 @@ VkResult syncImageToColorBuffer( uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, int* pNativeFenceFd, - AndroidNativeBufferInfo* anbInfo); + std::shared_ptr<AndroidNativeBufferInfo> anbInfo); } // namespace goldfish_vk diff --git a/stream-servers/vulkan/VkDecoderGlobalState.cpp b/stream-servers/vulkan/VkDecoderGlobalState.cpp index 835aa870..31f840cc 100644 --- a/stream-servers/vulkan/VkDecoderGlobalState.cpp +++ b/stream-servers/vulkan/VkDecoderGlobalState.cpp @@ -1559,7 +1559,7 @@ public: } cmpInfo.device = device; - AndroidNativeBufferInfo anbInfo; + AndroidNativeBufferInfo* anbInfo = new AndroidNativeBufferInfo; const VkNativeBufferANDROID* nativeBufferANDROID = vk_find_struct<VkNativeBufferANDROID>(pCreateInfo); @@ -1572,9 +1572,9 @@ public: createRes = prepareAndroidNativeBufferImage( vk, device, pCreateInfo, nativeBufferANDROID, pAllocator, - memProps, &anbInfo); + memProps, anbInfo); if (createRes == VK_SUCCESS) { - *pImage = anbInfo.image; + *pImage = anbInfo->image; } } else { createRes = @@ -1589,7 +1589,9 @@ public: } auto& imageInfo = mImageInfo[*pImage]; - imageInfo.anbInfo = anbInfo; + + if (anbInfo) imageInfo.anbInfo.reset(anbInfo); + imageInfo.cmpInfo = cmpInfo; *pImage = new_boxed_non_dispatchable_VkImage(*pImage); @@ -1613,9 +1615,7 @@ public: auto info = it->second; - if (info.anbInfo.image) { - teardownAndroidNativeBufferImage(vk, &info.anbInfo); - } else { + if (!info.anbInfo) { if (info.cmpInfo.isCompressed) { CompressedImageInfo& cmpInfo = info.cmpInfo; if (image != cmpInfo.decompImg) { @@ -1744,9 +1744,10 @@ public: pCreateInfo = &createInfo; } } - if (imageInfoIt->second.anbInfo.externallyBacked) { + if (imageInfoIt->second.anbInfo && + imageInfoIt->second.anbInfo->externallyBacked) { createInfo = *pCreateInfo; - createInfo.format = imageInfoIt->second.anbInfo.vkFormat; + createInfo.format = imageInfoIt->second.anbInfo->vkFormat; pCreateInfo = &createInfo; } @@ -3470,7 +3471,7 @@ public: return VK_ERROR_INITIALIZATION_FAILED; } - AndroidNativeBufferInfo* anbInfo = &imageInfo->anbInfo; + AndroidNativeBufferInfo* anbInfo = imageInfo->anbInfo.get(); return setAndroidNativeImageSemaphoreSignaled( @@ -3499,7 +3500,7 @@ public: } auto imageInfo = android::base::find(mImageInfo, image); - AndroidNativeBufferInfo* anbInfo = &imageInfo->anbInfo; + auto anbInfo = imageInfo->anbInfo; return syncImageToColorBuffer( @@ -4712,6 +4713,59 @@ public: return vk->vkGetFenceStatus(device, fence); } + VkResult waitQsri(VkImage boxed_image, uint64_t timeout) { + (void)timeout; // TODO + + AutoLock lock(mLock); + + VkImage image = unbox_VkImage(boxed_image); + + if (mLogging) { + fprintf(stderr, "%s: for boxed image 0x%llx image %p\n", + __func__, (unsigned long long)boxed_image, image); + } + + if (image == VK_NULL_HANDLE || mImageInfo.find(image) == mImageInfo.end()) { + // No image + return VK_SUCCESS; + } + + auto anbInfo = mImageInfo[image].anbInfo; // shared ptr, take ref + lock.unlock(); + + if (!anbInfo) { + fprintf(stderr, "%s: warning: image %p doesn't ahve anb info\n", __func__, image); + return VK_SUCCESS; + } + if (!anbInfo->vk) { + fprintf(stderr, "%s:%p warning: image %p anb info not initialized\n", __func__, anbInfo.get(), image); + return VK_SUCCESS; + } + // Could be null or mismatched image, check later + if (image != anbInfo->image) { + fprintf(stderr, "%s:%p warning: image %p anb info has wrong image: %p\n", __func__, anbInfo.get(), image, anbInfo->image); + return VK_SUCCESS; + } + + AutoLock qsriLock(anbInfo->qsriWaitInfo.lock); + ++anbInfo->qsriWaitInfo.requestedPresentCount; + uint64_t targetPresentCount = anbInfo->qsriWaitInfo.requestedPresentCount; + + if (mLogging) { + fprintf(stderr, "%s:%p New target present count %llu\n", + __func__, anbInfo.get(), (unsigned long long)targetPresentCount); + } + + anbInfo->qsriWaitInfo.cv.wait(&anbInfo->qsriWaitInfo.lock, [anbInfo, targetPresentCount] { + return targetPresentCount <= anbInfo->qsriWaitInfo.presentCount; + }); + + if (mLogging) { + fprintf(stderr, "%s:%p Done waiting\n", __func__, anbInfo.get()); + } + return VK_SUCCESS; + } + #define GUEST_EXTERNAL_MEMORY_HANDLE_TYPES \ (VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID | \ VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA | \ @@ -6430,7 +6484,7 @@ private: }; struct ImageInfo { - AndroidNativeBufferInfo anbInfo; + std::shared_ptr<AndroidNativeBufferInfo> anbInfo; CompressedImageInfo cmpInfo; }; @@ -7716,6 +7770,10 @@ VkResult VkDecoderGlobalState::getFenceStatus(VkFence boxed_fence) { return mImpl->getFenceStatus(boxed_fence); } +VkResult VkDecoderGlobalState::waitQsri(VkImage image, uint64_t timeout) { + return mImpl->waitQsri(image, timeout); +} + void VkDecoderGlobalState::deviceMemoryTransform_tohost( VkDeviceMemory* memory, uint32_t memoryCount, VkDeviceSize* offset, uint32_t offsetCount, diff --git a/stream-servers/vulkan/VkDecoderGlobalState.h b/stream-servers/vulkan/VkDecoderGlobalState.h index f2864e57..6cbf223f 100644 --- a/stream-servers/vulkan/VkDecoderGlobalState.h +++ b/stream-servers/vulkan/VkDecoderGlobalState.h @@ -780,6 +780,13 @@ public: VkResult getFenceStatus(VkFence boxed_fence); + // Wait for present (vkQueueSignalReleaseImageANDROID). This explicitly + // requires the image to be presented again versus how many times it's been + // presented so far, so it ends up incrementing a "target present count" + // for this image, and then waiting for the image to get vkQSRI'ed at least + // that many times. + VkResult waitQsri(VkImage boxed_image, uint64_t timeout); + // Transformations void deviceMemoryTransform_tohost( VkDeviceMemory* memory, uint32_t memoryCount, |