summaryrefslogtreecommitdiff
path: root/stream-servers/vulkan
diff options
context:
space:
mode:
authorLingfeng Yang <lfy@google.com>2021-07-15 16:50:37 -0700
committerLingfeng Yang <lfy@google.com>2021-07-21 13:51:54 -0700
commit9e750257b11b42bf7a49059db8533c935d3cc2db (patch)
tree8179a6d305432e3d07b9960a22ed3ef84ad085ef /stream-servers/vulkan
parentaf686801c2caaade06e2adeccae04fa77043b4d9 (diff)
downloadvulkan-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.cpp120
-rw-r--r--stream-servers/vulkan/VkAndroidNativeBuffer.h60
-rw-r--r--stream-servers/vulkan/VkDecoderGlobalState.cpp82
-rw-r--r--stream-servers/vulkan/VkDecoderGlobalState.h7
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,