Commit 6d94471b by Courtney Goeltzenleuchter Committed by Commit Bot

Vulkan: Eliminate fence wait from SyncVk

Waiting on a fence is problematic if using threaded worker to submit work since code needs to know if the work has been submitted or not before doing the wait. Eliminate the wait by using a serial if available or if no serial check the file descriptor directly. If no serial it's because we are waiting on an imported file descriptor. Could call fence.wait in that case but can also wait on the file descriptor. Test: angle_end2end_tests --gtest_filter=EGLSyncTest.*/ES2_Vulkan Bug: b/170312581 Change-Id: I392a5e73ac8f851d0d5bc53f06063568c0c90d2c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2579042Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Courtney Goeltzenleuchter <courtneygo@google.com>
parent f6df8692
...@@ -16,11 +16,60 @@ ...@@ -16,11 +16,60 @@
#include "libANGLE/renderer/vulkan/DisplayVk.h" #include "libANGLE/renderer/vulkan/DisplayVk.h"
#if !defined(ANGLE_PLATFORM_WINDOWS) #if !defined(ANGLE_PLATFORM_WINDOWS)
# include <poll.h>
# include <unistd.h> # include <unistd.h>
#else #else
# include <io.h> # include <io.h>
#endif #endif
namespace
{
// Wait for file descriptor to be signaled
VkResult SyncWait(int fd, uint64_t timeoutNs)
{
#if !defined(ANGLE_PLATFORM_WINDOWS)
struct pollfd fds;
int ret;
// Convert nanoseconds to milliseconds
int timeoutMs = static_cast<int>(timeoutNs / 1000000);
// If timeoutNs was non-zero but less than one millisecond, make it a millisecond.
if (timeoutNs > 0 && timeoutNs < 1000000)
{
timeoutMs = 1;
}
ASSERT(fd >= 0);
fds.fd = fd;
fds.events = POLLIN;
do
{
ret = poll(&fds, 1, timeoutMs);
if (ret > 0)
{
if (fds.revents & (POLLERR | POLLNVAL))
{
return VK_ERROR_UNKNOWN;
}
return VK_SUCCESS;
}
else if (ret == 0)
{
return VK_TIMEOUT;
}
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
return VK_ERROR_UNKNOWN;
#else
UNREACHABLE();
return VK_TIMEOUT;
#endif
}
} // anonymous namespace
namespace rx namespace rx
{ {
namespace vk namespace vk
...@@ -32,13 +81,6 @@ SyncHelper::~SyncHelper() {} ...@@ -32,13 +81,6 @@ SyncHelper::~SyncHelper() {}
void SyncHelper::releaseToRenderer(RendererVk *renderer) void SyncHelper::releaseToRenderer(RendererVk *renderer)
{ {
renderer->collectGarbageAndReinit(&mUse, &mEvent); renderer->collectGarbageAndReinit(&mUse, &mEvent);
// TODO: https://issuetracker.google.com/170312581 - Currently just stalling on worker thread
// here to try and avoid race condition. If this works, need some alternate solution
if (renderer->getFeatures().asyncCommandQueue.enabled)
{
ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelper::releaseToRenderer");
(void)renderer->waitForCommandProcessorIdle(nullptr);
}
} }
angle::Result SyncHelper::initialize(ContextVk *contextVk) angle::Result SyncHelper::initialize(ContextVk *contextVk)
...@@ -164,6 +206,19 @@ angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int ...@@ -164,6 +206,19 @@ angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int
{ {
ASSERT(inFd >= kInvalidFenceFd); ASSERT(inFd >= kInvalidFenceFd);
// If valid FD provided by application - import it to fence.
if (inFd > kInvalidFenceFd)
{
// File descriptor ownership: EGL_ANDROID_native_fence_sync
// Whenever a file descriptor is passed into or returned from an
// EGL call in this extension, ownership of that file descriptor is
// transferred. The recipient of the file descriptor must close it when it is
// no longer needed, and the provider of the file descriptor must dup it
// before providing it if they require continued use of the native fence.
mNativeFenceFd = inFd;
return angle::Result::Continue;
}
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
VkDevice device = renderer->getDevice(); VkDevice device = renderer->getDevice();
...@@ -183,15 +238,7 @@ angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int ...@@ -183,15 +238,7 @@ angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int
// Initialize/create a VkFence handle // Initialize/create a VkFence handle
ANGLE_VK_TRY(contextVk, fence.get().init(device, fenceCreateInfo)); ANGLE_VK_TRY(contextVk, fence.get().init(device, fenceCreateInfo));
int importFenceFd = kInvalidFenceFd; // invalid FD provided by application - create one with fence.
// If valid FD provided by application - import it to fence.
if (inFd > kInvalidFenceFd)
{
importFenceFd = inFd;
}
// If invalid FD provided by application - create one with fence.
else
{
/* /*
Spec: "When a fence sync object is created or when an EGL native fence sync Spec: "When a fence sync object is created or when an EGL native fence sync
object is created with the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute set to object is created with the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute set to
...@@ -217,28 +264,9 @@ angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int ...@@ -217,28 +264,9 @@ angle::Result SyncHelperNativeFence::initializeWithFd(ContextVk *contextVk, int
fenceGetFdInfo.sType = VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR; fenceGetFdInfo.sType = VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR;
fenceGetFdInfo.fence = fence.get().getHandle(); fenceGetFdInfo.fence = fence.get().getHandle();
fenceGetFdInfo.handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR; fenceGetFdInfo.handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR;
ANGLE_VK_TRY(contextVk, fence.get().exportFd(device, fenceGetFdInfo, &importFenceFd)); ANGLE_VK_TRY(contextVk, fence.get().exportFd(device, fenceGetFdInfo, &mNativeFenceFd));
}
// Spec: Importing a fence payload from a file descriptor transfers ownership of the file
// descriptor from the application to the Vulkan implementation. The application must not
// perform any operations on the file descriptor after a successful import.
// Make a dup of importFenceFd before transferring ownership to created fence.
mNativeFenceFd = dup(importFenceFd);
// Import FD - after creating fence.
VkImportFenceFdInfoKHR importFenceFdInfo = {};
importFenceFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR;
importFenceFdInfo.pNext = nullptr;
importFenceFdInfo.fence = fence.get().getHandle();
importFenceFdInfo.flags = VK_FENCE_IMPORT_TEMPORARY_BIT_KHR;
importFenceFdInfo.handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
importFenceFdInfo.fd = importFenceFd;
ANGLE_VK_TRY(contextVk, fence.get().importFd(device, importFenceFdInfo));
mFenceWithFd = fence.release(); mFenceWithFd = fence.release();
retain(&contextVk->getResourceUseList());
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -272,21 +300,22 @@ angle::Result SyncHelperNativeFence::clientWait(Context *context, ...@@ -272,21 +300,22 @@ angle::Result SyncHelperNativeFence::clientWait(Context *context,
ANGLE_TRY(contextVk->flushImpl(nullptr)); ANGLE_TRY(contextVk->flushImpl(nullptr));
} }
// TODO: https://issuetracker.google.com/170312581 - If we are using worker need to wait for the VkResult status = VK_SUCCESS;
// commands to be issued before waiting on the fence. if (mUse.valid())
if (contextVk->getRenderer()->getFeatures().asyncCommandQueue.enabled)
{ {
ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelperNativeFence::clientWait"); // We have a valid serial to wait on
ANGLE_TRY(contextVk->getRenderer()->waitForCommandProcessorIdle(contextVk)); ANGLE_TRY(
renderer->waitForSerialWithUserTimeout(context, mUse.getSerial(), timeout, &status));
} }
else
{
// We need to wait on the file descriptor
// Wait for mFenceWithFd to be signaled. status = SyncWait(mNativeFenceFd, timeout);
VkResult status = mFenceWithFd.wait(renderer->getDevice(), timeout);
// Check for errors, but don't consider timeout as such.
if (status != VK_TIMEOUT) if (status != VK_TIMEOUT)
{ {
ANGLE_VK_TRY(context, status); ANGLE_VK_TRY(contextVk, status);
}
} }
*outResult = status; *outResult = status;
...@@ -295,11 +324,6 @@ angle::Result SyncHelperNativeFence::clientWait(Context *context, ...@@ -295,11 +324,6 @@ angle::Result SyncHelperNativeFence::clientWait(Context *context,
angle::Result SyncHelperNativeFence::serverWait(ContextVk *contextVk) angle::Result SyncHelperNativeFence::serverWait(ContextVk *contextVk)
{ {
if (!mFenceWithFd.valid())
{
return angle::Result::Stop;
}
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
VkDevice device = renderer->getDevice(); VkDevice device = renderer->getDevice();
...@@ -328,8 +352,16 @@ angle::Result SyncHelperNativeFence::serverWait(ContextVk *contextVk) ...@@ -328,8 +352,16 @@ angle::Result SyncHelperNativeFence::serverWait(ContextVk *contextVk)
angle::Result SyncHelperNativeFence::getStatus(Context *context, bool *signaled) const angle::Result SyncHelperNativeFence::getStatus(Context *context, bool *signaled) const
{ {
VkResult result = mFenceWithFd.getStatus(context->getDevice()); // We've got a serial, check if the serial is still in use
if (result != VK_SUCCESS && result != VK_NOT_READY) if (mUse.valid())
{
*signaled = !isCurrentlyInUse(context->getRenderer()->getLastCompletedQueueSerial());
return angle::Result::Continue;
}
// We don't have a serial, check status of the file descriptor
VkResult result = SyncWait(mNativeFenceFd, 0);
if (result != VK_TIMEOUT)
{ {
ANGLE_VK_TRY(context, result); ANGLE_VK_TRY(context, result);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment