mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-01 05:48:11 +03:00
Vulkan: Perform CPU wait in clientWait outside the global lock
Leverage UnlockedTailCall and move the CPU side wait during a clientWait outside of the global mutex lock. Bug: angleproject:8340 Tests: FenceSyncTest.BasicOperations* Tests: EGLSyncTest.EglClientWaitSync* Change-Id: I8c05e62e74cc64d38bf8797d28faaf49135e71fc Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4851649 Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: mohan maiya <m.maiya@samsung.com> Reviewed-by: Charlie Lao <cclao@google.com>
This commit is contained in:
committed by
Angle LUCI CQ
parent
b185c3eada
commit
ce263437ca
@@ -6,7 +6,7 @@
|
||||
"scripts/entry_point_packed_gl_enums.json":
|
||||
"1c6b036918aabb9822a638fbf33f87f4",
|
||||
"scripts/generate_entry_points.py":
|
||||
"02bccd68542886dd17a751f98ad7d3eb",
|
||||
"64ef644064c7fcbbf89458dc53ca5c94",
|
||||
"scripts/gl_angle_ext.xml":
|
||||
"3d6d9529c6d0da797652c366ddaa9087",
|
||||
"scripts/registry_xml.py":
|
||||
@@ -130,11 +130,11 @@
|
||||
"src/libGLESv2/entry_points_cl_autogen.h":
|
||||
"dde2f94c3004874a7da995dae69da811",
|
||||
"src/libGLESv2/entry_points_egl_autogen.cpp":
|
||||
"ec731a77790f0a557702b395d03af432",
|
||||
"66320459d4a7d1df208cf9fc15779b80",
|
||||
"src/libGLESv2/entry_points_egl_autogen.h":
|
||||
"3bc7a8df9deadd7cfd615d0cfad0c6a8",
|
||||
"src/libGLESv2/entry_points_egl_ext_autogen.cpp":
|
||||
"7d86e5a581ef3062202552542afe6755",
|
||||
"23f30e2c3e1cf0196e838cfecd8ac279",
|
||||
"src/libGLESv2/entry_points_egl_ext_autogen.h":
|
||||
"2d005f4cb16dcdd61e08cfec97a12f86",
|
||||
"src/libGLESv2/entry_points_gl_1_autogen.cpp":
|
||||
@@ -162,7 +162,7 @@
|
||||
"src/libGLESv2/entry_points_gles_2_0_autogen.h":
|
||||
"691c60c2dfed9beca68aa1f32aa2c71b",
|
||||
"src/libGLESv2/entry_points_gles_3_0_autogen.cpp":
|
||||
"3acd48e02ac5bb362c031b6f0b2c4b8b",
|
||||
"5d44e91d02b54ef46169e31f7631aad5",
|
||||
"src/libGLESv2/entry_points_gles_3_0_autogen.h":
|
||||
"4ac2582759cdc6a30f78f83ab684d555",
|
||||
"src/libGLESv2/entry_points_gles_3_1_autogen.cpp":
|
||||
|
||||
@@ -416,7 +416,7 @@ TEMPLATE_GLES_ENTRY_POINT_WITH_RETURN = """\
|
||||
{constext_lost_error_generator}
|
||||
returnValue = GetDefaultReturnValue<angle::EntryPoint::GL{name}, {return_type}>();
|
||||
}}
|
||||
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
|
||||
{epilog}
|
||||
return returnValue;
|
||||
}}
|
||||
"""
|
||||
@@ -3068,6 +3068,9 @@ def get_unlocked_tail_call(api, cmd_name):
|
||||
# - eglSwapBuffers, eglSwapBuffersWithDamageKHR and
|
||||
# eglSwapBuffersWithFrameTokenANGLE -> May throttle the CPU in tail call
|
||||
#
|
||||
# - eglClientWaitSyncKHR, eglClientWaitSync, glClientWaitSync -> May wait on
|
||||
# fence in tail call
|
||||
#
|
||||
if cmd_name in [
|
||||
'eglDestroySurface', 'eglMakeCurrent', 'eglReleaseThread', 'eglCreateWindowSurface',
|
||||
'eglCreatePlatformWindowSurface', 'eglCreatePlatformWindowSurfaceEXT',
|
||||
@@ -3076,6 +3079,9 @@ def get_unlocked_tail_call(api, cmd_name):
|
||||
]:
|
||||
return 'egl::Display::GetCurrentThreadUnlockedTailCall()->run(nullptr);'
|
||||
|
||||
if cmd_name in ['eglClientWaitSyncKHR', 'eglClientWaitSync', 'glClientWaitSync']:
|
||||
return 'egl::Display::GetCurrentThreadUnlockedTailCall()->run(&returnValue);'
|
||||
|
||||
# Otherwise assert that no tail calls where generated
|
||||
return 'ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());'
|
||||
|
||||
|
||||
@@ -68,6 +68,64 @@ VkResult SyncWaitFd(int fd, uint64_t timeoutNs, VkResult timeoutResult = VK_TIME
|
||||
#endif
|
||||
}
|
||||
|
||||
// Map VkResult to GLenum
|
||||
void MapVkResultToGlenum(VkResult vkResult, angle::Result angleResult, void *outResult)
|
||||
{
|
||||
GLenum *glEnumOut = static_cast<GLenum *>(outResult);
|
||||
ASSERT(glEnumOut);
|
||||
|
||||
if (angleResult != angle::Result::Continue)
|
||||
{
|
||||
*glEnumOut = GL_WAIT_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (vkResult)
|
||||
{
|
||||
case VK_EVENT_SET:
|
||||
*glEnumOut = GL_ALREADY_SIGNALED;
|
||||
break;
|
||||
case VK_SUCCESS:
|
||||
*glEnumOut = GL_CONDITION_SATISFIED;
|
||||
break;
|
||||
case VK_TIMEOUT:
|
||||
*glEnumOut = GL_TIMEOUT_EXPIRED;
|
||||
break;
|
||||
default:
|
||||
*glEnumOut = GL_WAIT_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Map VkResult to EGLint
|
||||
void MapVkResultToEglint(VkResult result, angle::Result angleResult, void *outResult)
|
||||
{
|
||||
EGLint *eglIntOut = static_cast<EGLint *>(outResult);
|
||||
ASSERT(eglIntOut);
|
||||
|
||||
if (angleResult != angle::Result::Continue)
|
||||
{
|
||||
*eglIntOut = EGL_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case VK_EVENT_SET:
|
||||
// fall through. EGL doesn't differentiate between event being already set, or set
|
||||
// before timeout.
|
||||
case VK_SUCCESS:
|
||||
*eglIntOut = EGL_CONDITION_SATISFIED_KHR;
|
||||
break;
|
||||
case VK_TIMEOUT:
|
||||
*eglIntOut = EGL_TIMEOUT_EXPIRED_KHR;
|
||||
break;
|
||||
default:
|
||||
*eglIntOut = EGL_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace rx
|
||||
@@ -86,27 +144,25 @@ angle::Result SyncHelper::initialize(ContextVk *contextVk, bool isEGLSyncObject)
|
||||
return contextVk->onSyncObjectInit(this, isEGLSyncObject);
|
||||
}
|
||||
|
||||
angle::Result SyncHelper::clientWait(Context *context,
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
VkResult *outResult)
|
||||
angle::Result SyncHelper::prepareForClientWait(Context *context,
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
VkResult *resultOut)
|
||||
{
|
||||
RendererVk *renderer = context->getRenderer();
|
||||
|
||||
// If the event is already set, don't wait
|
||||
bool alreadySignaled = false;
|
||||
ANGLE_TRY(getStatus(context, contextVk, &alreadySignaled));
|
||||
if (alreadySignaled)
|
||||
{
|
||||
*outResult = VK_EVENT_SET;
|
||||
*resultOut = VK_EVENT_SET;
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
// If timeout is zero, there's no need to wait, so return timeout already.
|
||||
if (timeout == 0)
|
||||
{
|
||||
*outResult = VK_TIMEOUT;
|
||||
*resultOut = VK_TIMEOUT;
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
@@ -116,19 +172,74 @@ angle::Result SyncHelper::clientWait(Context *context,
|
||||
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPassIfDeferredSyncInit(
|
||||
RenderPassClosureReason::SyncObjectClientWait));
|
||||
}
|
||||
|
||||
// Submit commands if it was deferred on the context that issued the sync object
|
||||
ANGLE_TRY(submitSyncIfDeferred(contextVk, RenderPassClosureReason::SyncObjectClientWait));
|
||||
|
||||
VkResult status = VK_SUCCESS;
|
||||
ANGLE_TRY(renderer->waitForResourceUseToFinishWithUserTimeout(context, mUse, timeout, &status));
|
||||
*resultOut = VK_INCOMPLETE;
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
// Check for errors, but don't consider timeout as such.
|
||||
if (status != VK_TIMEOUT)
|
||||
angle::Result SyncHelper::clientWait(Context *context,
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
VkResult *resultOut)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelper clientWait");
|
||||
ANGLE_TRY(prepareForClientWait(context, contextVk, flushCommands, timeout, resultOut));
|
||||
|
||||
if (*resultOut == VK_INCOMPLETE)
|
||||
{
|
||||
ANGLE_VK_TRY(context, status);
|
||||
ANGLE_TRY(contextVk->getRenderer()->waitForResourceUseToFinishWithUserTimeout(
|
||||
context, mUse, timeout, resultOut));
|
||||
|
||||
// Check for errors, but don't consider timeout as such.
|
||||
if (*resultOut != VK_TIMEOUT)
|
||||
{
|
||||
ANGLE_VK_TRY(context, *resultOut);
|
||||
}
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result SyncHelper::clientWaitUnlocked(Context *context,
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
void *resultOut,
|
||||
MapVkResultToApiType mappingFunction)
|
||||
{
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "SyncHelper clientWaitUnlocked");
|
||||
VkResult status = VK_INCOMPLETE;
|
||||
ANGLE_TRY(prepareForClientWait(context, contextVk, flushCommands, timeout, &status));
|
||||
|
||||
if (status == VK_INCOMPLETE)
|
||||
{
|
||||
RendererVk *renderer = context->getRenderer();
|
||||
|
||||
// If we need to perform a CPU wait don't set the resultOut parameter passed into the
|
||||
// method, instead set the parameter passed into the unlocked tail call.
|
||||
auto clientWaitUnlocked = [renderer, context, mappingFunction, use = mUse,
|
||||
timeout](void *resultOut) {
|
||||
ANGLE_TRACE_EVENT0("gpu.angle", "UnlockedTailCall clientWait");
|
||||
ASSERT(resultOut);
|
||||
|
||||
VkResult status = VK_INCOMPLETE;
|
||||
angle::Result angleResult =
|
||||
renderer->waitForResourceUseToFinishWithUserTimeout(context, use, timeout, &status);
|
||||
mappingFunction(status, angleResult, resultOut);
|
||||
};
|
||||
|
||||
egl::Display::GetCurrentThreadUnlockedTailCall()->add(clientWaitUnlocked);
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
mappingFunction(status, angle::Result::Continue, resultOut);
|
||||
}
|
||||
|
||||
*outResult = status;
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
@@ -343,7 +454,7 @@ angle::Result SyncHelperNativeFence::clientWait(Context *context,
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
VkResult *outResult)
|
||||
VkResult *resultOut)
|
||||
{
|
||||
RendererVk *renderer = context->getRenderer();
|
||||
|
||||
@@ -352,14 +463,14 @@ angle::Result SyncHelperNativeFence::clientWait(Context *context,
|
||||
ANGLE_TRY(getStatus(context, contextVk, &alreadySignaled));
|
||||
if (alreadySignaled)
|
||||
{
|
||||
*outResult = VK_SUCCESS;
|
||||
*resultOut = VK_SUCCESS;
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
// If timeout is zero, there's no need to wait, so return timeout already.
|
||||
if (timeout == 0)
|
||||
{
|
||||
*outResult = VK_TIMEOUT;
|
||||
*resultOut = VK_TIMEOUT;
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
@@ -369,16 +480,31 @@ angle::Result SyncHelperNativeFence::clientWait(Context *context,
|
||||
contextVk->flushImpl(nullptr, nullptr, RenderPassClosureReason::SyncObjectClientWait));
|
||||
}
|
||||
|
||||
VkResult status = mExternalFence->wait(renderer->getDevice(), timeout);
|
||||
if (status != VK_TIMEOUT)
|
||||
*resultOut = mExternalFence->wait(renderer->getDevice(), timeout);
|
||||
if (*resultOut != VK_TIMEOUT)
|
||||
{
|
||||
ANGLE_VK_TRY(contextVk, status);
|
||||
ANGLE_VK_TRY(contextVk, *resultOut);
|
||||
}
|
||||
|
||||
*outResult = status;
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
angle::Result SyncHelperNativeFence::clientWaitUnlocked(Context *context,
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
void *resultOut,
|
||||
MapVkResultToApiType mappingFunction)
|
||||
{
|
||||
// Unlocked clientWait is not supported for SyncHelperNativeFence, yet.
|
||||
// For now call into clientWait(...)
|
||||
VkResult status = VK_INCOMPLETE;
|
||||
angle::Result angleResult = clientWait(context, contextVk, flushCommands, timeout, &status);
|
||||
|
||||
mappingFunction(status, angleResult, resultOut);
|
||||
return angleResult;
|
||||
}
|
||||
|
||||
angle::Result SyncHelperNativeFence::serverWait(ContextVk *contextVk)
|
||||
{
|
||||
RendererVk *renderer = contextVk->getRenderer();
|
||||
@@ -466,30 +592,10 @@ angle::Result SyncVk::clientWait(const gl::Context *context,
|
||||
ASSERT((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) == 0);
|
||||
|
||||
bool flush = (flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0;
|
||||
VkResult result;
|
||||
|
||||
ANGLE_TRY(mSyncHelper.clientWait(contextVk, contextVk, flush, static_cast<uint64_t>(timeout),
|
||||
&result));
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case VK_EVENT_SET:
|
||||
*outResult = GL_ALREADY_SIGNALED;
|
||||
return angle::Result::Continue;
|
||||
|
||||
case VK_SUCCESS:
|
||||
*outResult = GL_CONDITION_SATISFIED;
|
||||
return angle::Result::Continue;
|
||||
|
||||
case VK_TIMEOUT:
|
||||
*outResult = GL_TIMEOUT_EXPIRED;
|
||||
return angle::Result::Incomplete;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
*outResult = GL_WAIT_FAILED;
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
return mSyncHelper.clientWaitUnlocked(contextVk, contextVk, flush,
|
||||
static_cast<uint64_t>(timeout), outResult,
|
||||
MapVkResultToGlenum);
|
||||
}
|
||||
|
||||
angle::Result SyncVk::serverWait(const gl::Context *context, GLbitfield flags, GLuint64 timeout)
|
||||
@@ -569,33 +675,16 @@ egl::Error EGLSyncVk::clientWait(const egl::Display *display,
|
||||
ASSERT((flags & ~EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) == 0);
|
||||
|
||||
bool flush = (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) != 0;
|
||||
VkResult result;
|
||||
|
||||
ContextVk *contextVk = context ? vk::GetImpl(context) : nullptr;
|
||||
if (mSyncHelper->clientWait(vk::GetImpl(display), contextVk, flush,
|
||||
static_cast<uint64_t>(timeout), &result) == angle::Result::Stop)
|
||||
if (mSyncHelper->clientWaitUnlocked(vk::GetImpl(display), contextVk, flush,
|
||||
static_cast<uint64_t>(timeout), outResult,
|
||||
MapVkResultToEglint) == angle::Result::Stop)
|
||||
{
|
||||
return egl::Error(EGL_BAD_ALLOC);
|
||||
}
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case VK_EVENT_SET:
|
||||
// fall through. EGL doesn't differentiate between event being already set, or set
|
||||
// before timeout.
|
||||
case VK_SUCCESS:
|
||||
*outResult = EGL_CONDITION_SATISFIED_KHR;
|
||||
return egl::NoError();
|
||||
|
||||
case VK_TIMEOUT:
|
||||
*outResult = EGL_TIMEOUT_EXPIRED_KHR;
|
||||
return egl::NoError();
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
*outResult = EGL_FALSE;
|
||||
return egl::Error(EGL_BAD_ALLOC);
|
||||
}
|
||||
return egl::NoError();
|
||||
}
|
||||
|
||||
egl::Error EGLSyncVk::serverWait(const egl::Display *display,
|
||||
|
||||
@@ -51,7 +51,8 @@ class ExternalFence final : angle::NonCopyable
|
||||
int mFenceFd;
|
||||
};
|
||||
|
||||
using SharedExternalFence = std::shared_ptr<ExternalFence>;
|
||||
using SharedExternalFence = std::shared_ptr<ExternalFence>;
|
||||
using MapVkResultToApiType = std::function<void(VkResult, angle::Result, void *)>;
|
||||
|
||||
class SyncHelperInterface : angle::NonCopyable
|
||||
{
|
||||
@@ -65,6 +66,12 @@ class SyncHelperInterface : angle::NonCopyable
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
VkResult *outResult) = 0;
|
||||
virtual angle::Result clientWaitUnlocked(Context *context,
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
void *outResult,
|
||||
MapVkResultToApiType mappingFunction) = 0;
|
||||
virtual angle::Result serverWait(ContextVk *contextVk) = 0;
|
||||
virtual angle::Result getStatus(Context *context, ContextVk *contextVk, bool *signaledOut) = 0;
|
||||
virtual angle::Result dupNativeFenceFD(Context *context, int *fdOut) const = 0;
|
||||
@@ -89,7 +96,13 @@ class SyncHelper final : public vk::Resource, public SyncHelperInterface
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
VkResult *outResult) override;
|
||||
VkResult *resultOut) override;
|
||||
angle::Result clientWaitUnlocked(Context *context,
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
void *resultOut,
|
||||
MapVkResultToApiType mappingFunction) override;
|
||||
angle::Result serverWait(ContextVk *contextVk) override;
|
||||
angle::Result getStatus(Context *context, ContextVk *contextVk, bool *signaledOut) override;
|
||||
angle::Result dupNativeFenceFD(Context *context, int *fdOut) const override
|
||||
@@ -99,6 +112,11 @@ class SyncHelper final : public vk::Resource, public SyncHelperInterface
|
||||
|
||||
private:
|
||||
angle::Result submitSyncIfDeferred(ContextVk *contextVk, RenderPassClosureReason reason);
|
||||
angle::Result prepareForClientWait(Context *context,
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
VkResult *resultOut);
|
||||
};
|
||||
|
||||
// Implementation of sync types: EGLSync(EGL_SYNC_ANDROID_NATIVE_FENCE_ANDROID).
|
||||
@@ -118,7 +136,13 @@ class SyncHelperNativeFence final : public SyncHelperInterface
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
VkResult *outResult) override;
|
||||
VkResult *resultOut) override;
|
||||
angle::Result clientWaitUnlocked(Context *context,
|
||||
ContextVk *contextVk,
|
||||
bool flushCommands,
|
||||
uint64_t timeout,
|
||||
void *resultOut,
|
||||
MapVkResultToApiType mappingFunction) override;
|
||||
angle::Result serverWait(ContextVk *contextVk) override;
|
||||
angle::Result getStatus(Context *context, ContextVk *contextVk, bool *signaledOut) override;
|
||||
angle::Result dupNativeFenceFD(Context *context, int *fdOut) const override;
|
||||
|
||||
@@ -28,16 +28,37 @@ EGLint ClientWaitSyncKHR(Thread *thread,
|
||||
EGLint flags,
|
||||
EGLTimeKHR timeout)
|
||||
{
|
||||
ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglClientWaitSync",
|
||||
ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglClientWaitSyncKHR",
|
||||
GetDisplayIfValid(display), EGL_FALSE);
|
||||
gl::Context *currentContext = thread->getContext();
|
||||
EGLint syncStatus = EGL_FALSE;
|
||||
Sync *sync = display->getSync(syncID);
|
||||
ANGLE_EGL_TRY_RETURN(thread,
|
||||
sync->clientWait(display, currentContext, flags, timeout, &syncStatus),
|
||||
"eglClientWaitSync", GetSyncIfValid(display, syncID), EGL_FALSE);
|
||||
"eglClientWaitSyncKHR", GetSyncIfValid(display, syncID), EGL_FALSE);
|
||||
|
||||
thread->setSuccess();
|
||||
// When performing CPU wait through UnlockedTailCall we need to handle any error conditions
|
||||
if (egl::Display::GetCurrentThreadUnlockedTailCall()->any())
|
||||
{
|
||||
auto handleErrorStatus = [thread, display, syncID](void *result) {
|
||||
EGLint *eglResult = static_cast<EGLint *>(result);
|
||||
ASSERT(eglResult);
|
||||
if (*eglResult == EGL_FALSE)
|
||||
{
|
||||
thread->setError(egl::Error(EGL_BAD_ALLOC), "eglClientWaitSyncKHR",
|
||||
GetSyncIfValid(display, syncID));
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->setSuccess();
|
||||
}
|
||||
};
|
||||
egl::Display::GetCurrentThreadUnlockedTailCall()->add(handleErrorStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->setSuccess();
|
||||
}
|
||||
return syncStatus;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,28 @@ EGLint ClientWaitSync(Thread *thread,
|
||||
thread, syncObject->clientWait(display, currentContext, flags, timeout, &syncStatus),
|
||||
"eglClientWaitSync", GetSyncIfValid(display, syncID), EGL_FALSE);
|
||||
|
||||
thread->setSuccess();
|
||||
// When performing CPU wait through UnlockedTailCall we need to handle any error conditions
|
||||
if (egl::Display::GetCurrentThreadUnlockedTailCall()->any())
|
||||
{
|
||||
auto handleErrorStatus = [thread, display, syncID](void *result) {
|
||||
EGLint *eglResult = static_cast<EGLint *>(result);
|
||||
ASSERT(eglResult);
|
||||
if (*eglResult == EGL_FALSE)
|
||||
{
|
||||
thread->setError(egl::Error(EGL_BAD_ALLOC), "eglClientWaitSync",
|
||||
GetSyncIfValid(display, syncID));
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->setSuccess();
|
||||
}
|
||||
};
|
||||
egl::Display::GetCurrentThreadUnlockedTailCall()->add(handleErrorStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->setSuccess();
|
||||
}
|
||||
return syncStatus;
|
||||
}
|
||||
|
||||
|
||||
@@ -1002,7 +1002,7 @@ EGLint EGLAPIENTRY EGL_ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags
|
||||
ANGLE_CAPTURE_EGL(ClientWaitSync, true, thread, dpyPacked, syncPacked, flags, timeout,
|
||||
returnValue);
|
||||
}
|
||||
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
|
||||
egl::Display::GetCurrentThreadUnlockedTailCall()->run(&returnValue);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1422,7 +1422,7 @@ EGLint EGLAPIENTRY EGL_ClientWaitSyncKHR(EGLDisplay dpy,
|
||||
ANGLE_CAPTURE_EGL(ClientWaitSyncKHR, true, thread, dpyPacked, syncPacked, flags, timeout,
|
||||
returnValue);
|
||||
}
|
||||
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
|
||||
egl::Display::GetCurrentThreadUnlockedTailCall()->run(&returnValue);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -408,7 +408,7 @@ GLenum GL_APIENTRY GL_ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 tim
|
||||
GenerateContextLostErrorOnCurrentGlobalContext();
|
||||
returnValue = GetDefaultReturnValue<angle::EntryPoint::GLClientWaitSync, GLenum>();
|
||||
}
|
||||
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
|
||||
egl::Display::GetCurrentThreadUnlockedTailCall()->run(&returnValue);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -236,6 +236,57 @@ TEST_P(EGLSyncTest, BasicOperations)
|
||||
EXPECT_EGL_TRUE(eglDestroySyncKHR(display, sync));
|
||||
}
|
||||
|
||||
// Test that eglClientWaitSync* APIs work.
|
||||
TEST_P(EGLSyncTest, EglClientWaitSync)
|
||||
{
|
||||
ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension());
|
||||
|
||||
EGLDisplay display = getEGLWindow()->getDisplay();
|
||||
ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
|
||||
|
||||
// Test eglClientWaitSyncKHR
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
{
|
||||
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
drawQuad(greenProgram, std::string(essl1_shaders::PositionAttrib()), 0.0f);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
// Don't wait forever to make sure the test terminates
|
||||
constexpr GLuint64 kTimeout = 1'000'000'000; // 1 second
|
||||
EGLSyncKHR clientWaitSync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
|
||||
EXPECT_NE(clientWaitSync, EGL_NO_SYNC_KHR);
|
||||
|
||||
ASSERT_EQ(EGL_CONDITION_SATISFIED_KHR,
|
||||
eglClientWaitSyncKHR(display, clientWaitSync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
|
||||
kTimeout));
|
||||
|
||||
EXPECT_EGL_TRUE(eglDestroySyncKHR(display, clientWaitSync));
|
||||
ASSERT_EGL_SUCCESS();
|
||||
}
|
||||
|
||||
// Test eglClientWaitSync
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
{
|
||||
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
drawQuad(greenProgram, std::string(essl1_shaders::PositionAttrib()), 0.0f);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
// Don't wait forever to make sure the test terminates
|
||||
constexpr GLuint64 kTimeout = 1'000'000'000; // 1 second
|
||||
EGLSyncKHR clientWaitSync = eglCreateSync(display, EGL_SYNC_FENCE, nullptr);
|
||||
EXPECT_NE(clientWaitSync, EGL_NO_SYNC);
|
||||
|
||||
ASSERT_EQ(
|
||||
EGL_CONDITION_SATISFIED,
|
||||
eglClientWaitSync(display, clientWaitSync, EGL_SYNC_FLUSH_COMMANDS_BIT, kTimeout));
|
||||
|
||||
EXPECT_EGL_TRUE(eglDestroySync(display, clientWaitSync));
|
||||
ASSERT_EGL_SUCCESS();
|
||||
}
|
||||
}
|
||||
|
||||
// Test eglWaitClient api
|
||||
TEST_P(EGLSyncTest, WaitClient)
|
||||
{
|
||||
|
||||
@@ -265,11 +265,26 @@ TEST_P(FenceSyncTest, BasicOperations)
|
||||
|
||||
ASSERT_GLENUM_EQ(GL_SIGNALED, value);
|
||||
|
||||
ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||
drawQuad(greenProgram, std::string(essl1_shaders::PositionAttrib()), 0.0f);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
GLsync clientWaitSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
// Don't wait forever to make sure the test terminates
|
||||
constexpr GLuint64 kTimeout = 1'000'000'000; // 1 second
|
||||
GLenum clientWaitResult =
|
||||
glClientWaitSync(clientWaitSync, GL_SYNC_FLUSH_COMMANDS_BIT, kTimeout);
|
||||
EXPECT_GL_NO_ERROR();
|
||||
EXPECT_TRUE(clientWaitResult == GL_CONDITION_SATISFIED ||
|
||||
clientWaitResult == GL_ALREADY_SIGNALED);
|
||||
|
||||
glDeleteSync(clientWaitSync);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user