summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--host-common/FeatureControlDefHost.h1
-rw-r--r--stream-servers/FrameBuffer.cpp10
-rw-r--r--stream-servers/FrameBuffer.h2
-rw-r--r--stream-servers/GfxStreamBackend.cpp6
-rw-r--r--stream-servers/RenderControl.cpp13
-rw-r--r--stream-servers/RendererImpl.cpp6
-rw-r--r--stream-servers/SyncThread.cpp84
-rw-r--r--stream-servers/SyncThread.h11
-rw-r--r--stream-servers/virtio-gpu-gfxstream-renderer.cpp47
-rw-r--r--stream-servers/virtio_gpu_ops.h6
-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
14 files changed, 405 insertions, 50 deletions
diff --git a/host-common/FeatureControlDefHost.h b/host-common/FeatureControlDefHost.h
index 1a431fe7..8b437887 100644
--- a/host-common/FeatureControlDefHost.h
+++ b/host-common/FeatureControlDefHost.h
@@ -72,3 +72,4 @@ FEATURE_CONTROL_ITEM(GuestUsesAngle)
FEATURE_CONTROL_ITEM(VirtioVsockPipe)
FEATURE_CONTROL_ITEM(S3tcTextureSupport)
FEATURE_CONTROL_ITEM(VulkanNativeSwapchain)
+FEATURE_CONTROL_ITEM(VirtioGpuFenceContexts)
diff --git a/stream-servers/FrameBuffer.cpp b/stream-servers/FrameBuffer.cpp
index 13baee8a..1e10c8d4 100644
--- a/stream-servers/FrameBuffer.cpp
+++ b/stream-servers/FrameBuffer.cpp
@@ -3337,6 +3337,16 @@ void FrameBuffer::asyncWaitForGpuVulkanWithCb(uint64_t deviceHandle, uint64_t fe
SyncThread::get()->triggerWaitVkWithCompletionCallback((VkFence)fenceHandle, std::move(cb));
}
+void FrameBuffer::asyncWaitForGpuVulkanQsriWithCb(uint64_t image, FenceCompletionCallback cb) {
+ SyncThread::get()->triggerWaitVkQsriWithCompletionCallback((VkImage)image, std::move(cb));
+}
+
+void FrameBuffer::waitForGpuVulkanQsri(uint64_t image) {
+ (void)image;
+ // Signal immediately, because this was a sync wait and it's vulkan.
+ SyncThread::get()->triggerBlockedWaitNoTimeline(nullptr);
+}
+
void FrameBuffer::setGuestManagedColorBufferLifetime(bool guestManaged) {
m_guestManagedColorBufferLifetime = guestManaged;
}
diff --git a/stream-servers/FrameBuffer.h b/stream-servers/FrameBuffer.h
index ab215632..37951cf8 100644
--- a/stream-servers/FrameBuffer.h
+++ b/stream-servers/FrameBuffer.h
@@ -579,6 +579,8 @@ class FrameBuffer {
void waitForGpuVulkan(uint64_t deviceHandle, uint64_t fenceHandle);
void asyncWaitForGpuWithCb(uint64_t eglsync, FenceCompletionCallback cb);
void asyncWaitForGpuVulkanWithCb(uint64_t deviceHandle, uint64_t fenceHandle, FenceCompletionCallback cb);
+ void asyncWaitForGpuVulkanQsriWithCb(uint64_t image, FenceCompletionCallback cb);
+ void waitForGpuVulkanQsri(uint64_t image);
void setGuestManagedColorBufferLifetime(bool guestManaged);
diff --git a/stream-servers/GfxStreamBackend.cpp b/stream-servers/GfxStreamBackend.cpp
index 19fa7460..6ef5dd6a 100644
--- a/stream-servers/GfxStreamBackend.cpp
+++ b/stream-servers/GfxStreamBackend.cpp
@@ -396,6 +396,12 @@ extern "C" VG_EXPORT void gfxstream_backend_init(
useVulkanNativeSwapchain);
feature_set_enabled_override(
kFeature_VulkanBatchedDescriptorSetUpdate, true);
+ // TODO: Strictly speaking, renderer_flags check is insufficient because
+ // fence contexts require us to be running a new-enough guest kernel.
+ feature_set_enabled_override(
+ kFeature_VirtioGpuFenceContexts,
+ !syncFdDisabledByFlag &&
+ (renderer_flags & GFXSTREAM_RENDERER_FLAGS_ASYNC_FENCE_CB));
if (useVulkanNativeSwapchain && !enableVk) {
fprintf(stderr,
diff --git a/stream-servers/RenderControl.cpp b/stream-servers/RenderControl.cpp
index 540bfcf2..b03ac7ee 100644
--- a/stream-servers/RenderControl.cpp
+++ b/stream-servers/RenderControl.cpp
@@ -350,7 +350,8 @@ static bool shouldEnableAsyncQueueSubmit() {
static bool shouldEnableVulkanAsyncQsri() {
return shouldEnableVulkan() &&
(feature_is_enabled(kFeature_GLAsyncSwap) ||
- feature_is_enabled(kFeature_VirtioGpuNativeSync));
+ (feature_is_enabled(kFeature_VirtioGpuNativeSync) &&
+ feature_is_enabled(kFeature_VirtioGpuFenceContexts)));
}
const char* maxVersionToFeatureString(GLESDispatchMaxVersion version) {
@@ -619,12 +620,10 @@ static EGLint rcGetGLString(EGLenum name, void* buffer, EGLint bufferSize) {
glStr += " ";
}
- // Bug: 193809913
- // Only switch on after everything else about this is merged / works.
- // if (vulkanAsyncQsri) {
- // glStr += kVulkanAsyncQsri;
- // glStr += " ";
- // }
+ if (vulkanAsyncQsri && name == GL_EXTENSIONS) {
+ glStr += kVulkanAsyncQsri;
+ glStr += " ";
+ }
if (name == GL_EXTENSIONS) {
diff --git a/stream-servers/RendererImpl.cpp b/stream-servers/RendererImpl.cpp
index 5fc00128..29e417f1 100644
--- a/stream-servers/RendererImpl.cpp
+++ b/stream-servers/RendererImpl.cpp
@@ -598,6 +598,12 @@ static struct AndroidVirtioGpuOps sVirtioGpuOps = {
.async_wait_for_gpu_vulkan_with_cb = [](uint64_t device, uint64_t fence, FenceCompletionCallback cb) {
FrameBuffer::getFB()->asyncWaitForGpuVulkanWithCb(device, fence, cb);
},
+ .async_wait_for_gpu_vulkan_qsri_with_cb = [](uint64_t image, FenceCompletionCallback cb) {
+ FrameBuffer::getFB()->asyncWaitForGpuVulkanQsriWithCb(image, cb);
+ },
+ .wait_for_gpu_vulkan_qsri = [](uint64_t image) {
+ FrameBuffer::getFB()->waitForGpuVulkanQsri(image);
+ },
};
struct AndroidVirtioGpuOps* RendererImpl::getVirtioGpuOps() {
diff --git a/stream-servers/SyncThread.cpp b/stream-servers/SyncThread.cpp
index 30bb432c..8cfa2d58 100644
--- a/stream-servers/SyncThread.cpp
+++ b/stream-servers/SyncThread.cpp
@@ -140,6 +140,36 @@ void SyncThread::triggerWaitVkWithCompletionCallback(VkFence vkFence, FenceCompl
DPRINT("exit");
}
+void SyncThread::triggerWaitVkQsriWithCompletionCallback(VkImage vkImage, FenceCompletionCallback cb) {
+ DPRINT("fenceSyncInfo=0x%llx ...", fenceSync);
+ SyncThreadCmd to_send;
+ to_send.opCode = SYNC_THREAD_WAIT_VK_QSRI;
+ to_send.vkImage = vkImage;
+ to_send.useFenceCompletionCallback = true;
+ to_send.fenceCompletionCallback = cb;
+ DPRINT("opcode=%u", to_send.opCode);
+ sendAsync(to_send);
+ DPRINT("exit");
+}
+
+void SyncThread::triggerWaitVkQsriBlockedNoTimeline(VkImage vkImage) {
+ DPRINT("fenceSyncInfo=0x%llx ...", fenceSync);
+ SyncThreadCmd to_send;
+ to_send.opCode = SYNC_THREAD_WAIT_VK_QSRI;
+ to_send.vkImage = vkImage;
+ DPRINT("opcode=%u", to_send.opCode);
+ sendAndWaitForResult(to_send);
+ DPRINT("exit");
+}
+
+void SyncThread::triggerGeneral(FenceCompletionCallback cb) {
+ SyncThreadCmd to_send;
+ to_send.opCode = SYNC_THREAD_GENERAL;
+ to_send.useFenceCompletionCallback = true;
+ to_send.fenceCompletionCallback = cb;
+ sendAsync(to_send);
+}
+
void SyncThread::cleanup() {
DPRINT("enter");
SyncThreadCmd to_send;
@@ -336,6 +366,52 @@ int SyncThread::doSyncWaitVk(SyncThreadCmd* cmd) {
return result;
}
+int SyncThread::doSyncWaitVkQsri(SyncThreadCmd* cmd) {
+ DPRINT("enter");
+
+ auto decoder = goldfish_vk::VkDecoderGlobalState::get();
+ DPRINT("doSyncWaitVkQsri for image %p", cmd->vkImage);
+ auto result = decoder->waitQsri(cmd->vkImage, kDefaultTimeoutNsecs);
+ DPRINT("doSyncWaitVkQsri for image %p (done, do signal/callback)", cmd->vkImage);
+ if (result == VK_TIMEOUT) {
+ fprintf(stderr, "SyncThread::%s: SYNC_WAIT_VK_QSRI timeout: vkImage=%p\n",
+ __func__, cmd->vkImage);
+ } else if (result != VK_SUCCESS) {
+ fprintf(stderr, "SyncThread::%s: SYNC_WAIT_VK_QSRI error: %d vkImage=%p\n",
+ __func__, result, cmd->vkImage);
+ }
+
+ DPRINT("issue timeline increment");
+
+ // We always unconditionally increment timeline at this point, even
+ // if the call to vkWaitForFences returned abnormally.
+ // See comments in |doSyncWait| about the rationale.
+ if (cmd->useFenceCompletionCallback) {
+ DPRINT("wait done, use completion callback");
+ cmd->fenceCompletionCallback();
+ } else {
+ DPRINT("wait done, use goldfish sync timeline inc");
+ emugl::emugl_sync_timeline_inc(cmd->timeline, kTimelineInterval);
+ }
+
+ DPRINT("done timeline increment");
+
+ DPRINT("exit");
+ return result;
+}
+
+int SyncThread::doSyncGeneral(SyncThreadCmd* cmd) {
+ DPRINT("enter");
+ if (cmd->useFenceCompletionCallback) {
+ DPRINT("wait done, use completion callback");
+ cmd->fenceCompletionCallback();
+ } else {
+ DPRINT("warning, completion callback not provided in general op!");
+ }
+
+ return 0;
+}
+
void SyncThread::doSyncBlockedWaitNoTimeline(SyncThreadCmd* cmd) {
DPRINT("enter");
@@ -396,6 +472,14 @@ int SyncThread::doSyncThreadCmd(SyncThreadCmd* cmd) {
DPRINT("exec SYNC_THREAD_WAIT_VK");
result = doSyncWaitVk(cmd);
break;
+ case SYNC_THREAD_WAIT_VK_QSRI:
+ DPRINT("exec SYNC_THREAD_WAIT_VK_QSRI");
+ result = doSyncWaitVkQsri(cmd);
+ break;
+ case SYNC_THREAD_GENERAL:
+ DPRINT("exec SYNC_THREAD_GENERAL");
+ result = doSyncGeneral(cmd);
+ break;
case SYNC_THREAD_EXIT:
DPRINT("exec SYNC_THREAD_EXIT");
doExit(cmd);
diff --git a/stream-servers/SyncThread.h b/stream-servers/SyncThread.h
index 0e58f8c9..521dda0d 100644
--- a/stream-servers/SyncThread.h
+++ b/stream-servers/SyncThread.h
@@ -53,6 +53,10 @@ enum SyncThreadOpCode {
// and timeline handle.
// A fence FD object / Zircon eventpair in the guest is signaled.
SYNC_THREAD_WAIT_VK = 4,
+ // Command to wait on the presentation the given VkImage.
+ SYNC_THREAD_WAIT_VK_QSRI = 5,
+ // Command that consists only of a callback.
+ SYNC_THREAD_GENERAL = 6,
};
struct SyncThreadCmd {
@@ -65,6 +69,7 @@ struct SyncThreadCmd {
union {
FenceSync* fenceSync = nullptr;
VkFence vkFence;
+ VkImage vkImage;
};
uint64_t timeline = 0;
@@ -111,6 +116,10 @@ public:
// For use with virtio-gpu and async fence completion callback. This is async like triggerWait, but takes a fence completion callback instead of incrementing some timeline directly.
void triggerWaitWithCompletionCallback(FenceSync* fenceSync, FenceCompletionCallback);
void triggerWaitVkWithCompletionCallback(VkFence fenceHandle, FenceCompletionCallback);
+ void triggerWaitVkQsriWithCompletionCallback(VkImage image, FenceCompletionCallback);
+ void triggerWaitVkQsriBlockedNoTimeline(VkImage image);
+
+ void triggerGeneral(FenceCompletionCallback);
// |cleanup|: for use with destructors and other cleanup functions.
// it destroys the sync context and exits the sync thread.
@@ -152,6 +161,8 @@ private:
void doSyncContextInit(SyncThreadCmd* cmd);
void doSyncWait(SyncThreadCmd* cmd);
int doSyncWaitVk(SyncThreadCmd* cmd);
+ int doSyncWaitVkQsri(SyncThreadCmd* cmd);
+ int doSyncGeneral(SyncThreadCmd* cmd);
void doSyncBlockedWaitNoTimeline(SyncThreadCmd* cmd);
void doExit(SyncThreadCmd* cmd);
diff --git a/stream-servers/virtio-gpu-gfxstream-renderer.cpp b/stream-servers/virtio-gpu-gfxstream-renderer.cpp
index 6a2dcf76..0b752ba2 100644
--- a/stream-servers/virtio-gpu-gfxstream-renderer.cpp
+++ b/stream-servers/virtio-gpu-gfxstream-renderer.cpp
@@ -502,7 +502,7 @@ const uint32_t kVirtioGpuNativeSyncCreateImportFd = 0x9001;
const uint32_t kVirtioGpuNativeSyncVulkanCreateExportFd = 0xa000;
const uint32_t kVirtioGpuNativeSyncVulkanCreateImportFd = 0xa001;
-const uint32_t kVirtioGpuNativeSyncVulkanCreateExportFdForQueueSignalReleaseImage = 0xa002;
+const uint32_t kVirtioGpuNativeSyncVulkanQsriExport = 0xa002;
class PipeVirglRenderer {
public:
@@ -820,7 +820,7 @@ public:
AutoLock lock(mCtxPendingFencesLock);
mCtxNeededFencingTypes[ctxId] = CtxFencingType::AsyncSignal;
mVirtioGpuOps->async_wait_for_gpu_with_cb(sync_handle, [this, ctxId] {
- this->completionCallback(ctxId);
+ this->completionCallback(ctxId);
});
} else {
mVirtioGpuOps->wait_for_gpu(sync_handle);
@@ -839,28 +839,32 @@ public:
VGPLOG("wait for gpu vk ctx id %u", ctxId);
if (mUseAsyncFenceCb) {
+ AutoLock lock(mCtxPendingFencesLock);
+ mCtxNeededFencingTypes[ctxId] = CtxFencingType::AsyncSignal;
mVirtioGpuOps->async_wait_for_gpu_vulkan_with_cb(device_handle, fence_handle, [this, ctxId] {
- this->completionCallback(ctxId);
+ this->completionCallback(ctxId);
});
} else {
mVirtioGpuOps->wait_for_gpu_vulkan(device_handle, fence_handle);
}
break;
}
- // case kVirtioGpuNativeSyncVulkanCreateExportFdForQueueSignalReleaseImage: {
- // uint64_t queue_handle_lo = dwords[1];
- // uint64_t queue_handle_hi = dwords[2];
- // uint64_t queue_handle = convert32to64(device_handle_lo, device_handle_hi);
- // fprintf(stderr, "%s: wait for gpu vk qsri id %u queue 0x%llx\n", __func__, ctxId, (unsigned long long)queue_handle);
- // if (mUseAsyncFenceCb) {
- // mVirtioGpuOps->async_wait_for_gpu_vulkan_qsri_with_cb(queue_handle, [this, ctxId] {
- // this->completionCallback(ctxId);
- // });
- // } else {
- // mVirtioGpuOps->wait_for_gpu_vulkan_qsri(queue_handle);
- // }
- // break;
- // }
+ case kVirtioGpuNativeSyncVulkanQsriExport: {
+ uint64_t image_handle_lo = dwords[1];
+ uint64_t image_handle_hi = dwords[2];
+ uint64_t image_handle = convert32to64(image_handle_lo, image_handle_hi);
+ VGPLOG("wait for gpu vk qsri id %u image 0x%llx", ctxId, (unsigned long long)image_handle);
+ if (mUseAsyncFenceCb) {
+ AutoLock lock(mCtxPendingFencesLock);
+ mCtxNeededFencingTypes[ctxId] = CtxFencingType::AsyncSignal;
+ mVirtioGpuOps->async_wait_for_gpu_vulkan_qsri_with_cb(image_handle, [this, ctxId] {
+ this->completionCallback(ctxId);
+ });
+ } else {
+ mVirtioGpuOps->wait_for_gpu_vulkan_qsri(image_handle);
+ }
+ break;
+ }
default:
return -1;
}
@@ -919,8 +923,7 @@ public:
int contextCreateFence(uint32_t fence_id, uint32_t ctx_id, uint32_t fence_ctx_idx) {
AutoLock lock(mLock);
- fprintf(stderr, "%s: fence id %u ctx id %u fence_ctx_idx %u\n", __func__, fence_id, ctx_id, fence_ctx_idx);
- VGPLOG("fenceid: %u cmdtype: %u", fence_id, ctx_id);
+ VGPLOG("fenceid: %u cmdtype: %u fence_ctx_idx: %u", fence_id, ctx_id, fence_ctx_idx);
if (mUseAsyncFenceCb) {
fprintf(stderr, "%s: create fence using async fence cb\n", __func__);
if (0 == ctx_id) {
@@ -1679,7 +1682,11 @@ private:
if (pendingState.type == CtxFencingType::SyncSignal) {
VGPLOG("This was a sync signal, write fence, erase it and continue")
- mVirglRendererCallbacks.write_fence2(mCookie, fence_value, ctx_id, 0 /* ring_idx */);
+ if (mUseAsyncFenceCb) {
+ mVirglRendererCallbacks.write_fence2(mCookie, fence_value, ctx_id, 0 /* ring_idx */);
+ } else {
+ mVirglRendererCallbacks.write_fence(mCookie, fence_value);
+ }
it = pendingFencesThisCtx.erase(it);
} else {
if (CtxFencingType::AsyncSignal != pendingState.type) {
diff --git a/stream-servers/virtio_gpu_ops.h b/stream-servers/virtio_gpu_ops.h
index 8c08bacc..490036e0 100644
--- a/stream-servers/virtio_gpu_ops.h
+++ b/stream-servers/virtio_gpu_ops.h
@@ -89,6 +89,9 @@ using FenceCompletionCallback = std::function<void()>;
typedef void (*async_wait_for_gpu_with_cb_t)(uint64_t eglsync, FenceCompletionCallback);
typedef void (*async_wait_for_gpu_vulkan_with_cb_t)(uint64_t device, uint64_t fence, FenceCompletionCallback);
+typedef void (*async_wait_for_gpu_vulkan_qsri_with_cb_t)(uint64_t image, FenceCompletionCallback);
+typedef void (*wait_for_gpu_vulkan_qsri_t)(uint64_t image);
+
struct AndroidVirtioGpuOps {
create_color_buffer_with_handle_t create_color_buffer_with_handle;
open_color_buffer_t open_color_buffer;
@@ -113,4 +116,7 @@ struct AndroidVirtioGpuOps {
set_guest_managed_color_buffer_lifetime_t set_guest_managed_color_buffer_lifetime;
async_wait_for_gpu_with_cb_t async_wait_for_gpu_with_cb;
async_wait_for_gpu_vulkan_with_cb_t async_wait_for_gpu_vulkan_with_cb;
+
+ async_wait_for_gpu_vulkan_qsri_with_cb_t async_wait_for_gpu_vulkan_qsri_with_cb;
+ wait_for_gpu_vulkan_qsri_t wait_for_gpu_vulkan_qsri;
};
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,