Commit 535d4783 by Tim Van Patten Committed by Commit Bot

Vulkan: Flush if sync object is pending during SyncVk::getStatus()

When a glGetSynciv() is performed for GL_SYNC_STATUS, we should flush any pending commands if a sync object is pending a flush, since the caller is interested in the status of a fence. This will guarantee that the work is submitted to the hardware and eventually completes. This is accomplished by moving mSyncObjectPendingFlush from ContextVk to ShareGroupVk, so that any sync objects used by any contexts within the share group are submitted to hardware and the required work completes. Bug: angleproject:5306 Bug: angleproject:5425 Test: FenceSyncTest.BasicOperations Change-Id: I2e2681ad01fda429ba37f061c9bac5eb91f800fd Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2641095Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Tim Van Patten <timvp@google.com>
parent 26e02593
......@@ -373,7 +373,6 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mOutsideRenderPassCommands(nullptr),
mRenderPassCommands(nullptr),
mGpuEventsEnabled(false),
mSyncObjectPendingFlush(false),
mEGLSyncObjectPendingFlush(false),
mHasDeferredFlush(false),
mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()},
......@@ -694,7 +693,8 @@ angle::Result ContextVk::flush(const gl::Context *context)
// lands in the correct place within the command stream.
// EGL sync objects can span across context share groups, so don't defer flushes if there's one
// pending a flush.
if (mSyncObjectPendingFlush && context->isShared() && !mEGLSyncObjectPendingFlush)
if (getShareGroupVk()->isSyncObjectPendingFlush() && context->isShared() &&
!mEGLSyncObjectPendingFlush)
{
// Flush the commands to create a sync point in the command stream.
ANGLE_TRY(flushCommandsAndEndRenderPass());
......@@ -4278,8 +4278,8 @@ angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore)
// We must set this to false before calling flushCommandsAndEndRenderPass to prevent it from
// calling back to flushImpl.
mHasDeferredFlush = false;
mSyncObjectPendingFlush = false;
mHasDeferredFlush = false;
getShareGroupVk()->clearSyncObjectPendingFlush();
ANGLE_TRY(flushCommandsAndEndRenderPass());
......
......@@ -568,7 +568,7 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
const vk::PerfCounters &getPerfCounters() const { return mPerfCounters; }
vk::PerfCounters &getPerfCounters() { return mPerfCounters; }
void onSyncHelperInitialize() { mSyncObjectPendingFlush = true; }
void onSyncHelperInitialize() { getShareGroupVk()->setSyncObjectPendingFlush(); }
void onEGLSyncHelperInitialize() { mEGLSyncObjectPendingFlush = true; }
// Implementation of MultisampleTextureInitializer
......@@ -991,7 +991,6 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
// Track SyncHelper object been added into secondary command buffer that has not been flushed to
// vulkan.
bool mSyncObjectPendingFlush;
bool mEGLSyncObjectPendingFlush;
bool mHasDeferredFlush;
......
......@@ -284,6 +284,8 @@ void DisplayVk::populateFeatureList(angle::FeatureList *features)
mRenderer->getFeatures().populateFeatureList(features);
}
ShareGroupVk::ShareGroupVk() : mSyncObjectPendingFlush(false) {}
void ShareGroupVk::onDestroy(const egl::Display *display)
{
DisplayVk *displayVk = vk::GetImpl(display);
......
......@@ -25,7 +25,7 @@ using ShareContextSet = std::set<ContextVk *>;
class ShareGroupVk : public ShareGroupImpl
{
public:
ShareGroupVk() {}
ShareGroupVk();
void onDestroy(const egl::Display *display) override;
// PipelineLayoutCache and DescriptorSetLayoutCache can be shared between multiple threads
......@@ -44,6 +44,10 @@ class ShareGroupVk : public ShareGroupImpl
mResourceUseLists.emplace_back(std::move(resourceUseList));
}
bool isSyncObjectPendingFlush() { return mSyncObjectPendingFlush; }
void setSyncObjectPendingFlush() { mSyncObjectPendingFlush = true; }
void clearSyncObjectPendingFlush() { mSyncObjectPendingFlush = false; }
private:
// ANGLE uses a PipelineLayout cache to store compatible pipeline layouts.
PipelineLayoutCache mPipelineLayoutCache;
......@@ -57,6 +61,8 @@ class ShareGroupVk : public ShareGroupImpl
// List of resources currently used that need to be freed when any ContextVk in this
// ShareGroupVk submits the next command.
std::vector<vk::ResourceUseList> mResourceUseLists;
bool mSyncObjectPendingFlush;
};
class DisplayVk : public DisplayImpl, public vk::Context
......
......@@ -34,8 +34,14 @@ angle::Result FenceNVVk::set(const gl::Context *context, GLenum condition)
angle::Result FenceNVVk::test(const gl::Context *context, GLboolean *outFinished)
{
ContextVk *contextVk = vk::GetImpl(context);
if (contextVk->getShareGroupVk()->isSyncObjectPendingFlush())
{
ANGLE_TRY(contextVk->flushImpl(nullptr));
}
bool signaled = false;
ANGLE_TRY(mFenceSync.getStatus(vk::GetImpl(context), &signaled));
ANGLE_TRY(mFenceSync.getStatus(contextVk, &signaled));
ASSERT(outFinished);
*outFinished = signaled ? GL_TRUE : GL_FALSE;
......
......@@ -452,8 +452,14 @@ angle::Result SyncVk::serverWait(const gl::Context *context, GLbitfield flags, G
angle::Result SyncVk::getStatus(const gl::Context *context, GLint *outResult)
{
ContextVk *contextVk = vk::GetImpl(context);
if (contextVk->getShareGroupVk()->isSyncObjectPendingFlush())
{
ANGLE_TRY(contextVk->flushImpl(nullptr));
}
bool signaled = false;
ANGLE_TRY(mSyncHelper.getStatus(vk::GetImpl(context), &signaled));
ANGLE_TRY(mSyncHelper.getStatus(contextVk, &signaled));
*outResult = signaled ? GL_SIGNALED : GL_UNSIGNALED;
return angle::Result::Continue;
......
......@@ -230,9 +230,6 @@ TEST_P(FenceSyncTest, BasicQueries)
// Test that basic usage works and doesn't generate errors or crash
TEST_P(FenceSyncTest, BasicOperations)
{
// TODO(http://anglebug.com/5425): glClientWaitSync() returns GL_TIMEOUT_EXPIRED
ANGLE_SKIP_TEST_IF(IsAMD() && IsD3D11());
glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
......@@ -241,17 +238,28 @@ TEST_P(FenceSyncTest, BasicOperations)
glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
EXPECT_GL_NO_ERROR();
GLsizei length = 0;
GLint value = 0;
unsigned int loopCount = 0;
glFlush();
// Don't wait forever to make sure the test terminates
constexpr GLuint64 kTimeout = 1'000'000'000; // 1 second
GLint value = 0;
// Use 'loopCount' to make sure the test doesn't get stuck in an infinite loop
while (value != GL_SIGNALED && loopCount <= 1000000)
{
loopCount++;
glGetSynciv(sync, GL_SYNC_STATUS, 1, &length, &value);
ASSERT_GL_NO_ERROR();
}
ASSERT_GLENUM_EQ(GL_SIGNALED, value);
for (size_t i = 0; i < 20; i++)
{
glClear(GL_COLOR_BUFFER_BIT);
value = glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, kTimeout);
glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
EXPECT_GL_NO_ERROR();
ASSERT_TRUE(value == GL_CONDITION_SATISFIED || value == GL_ALREADY_SIGNALED);
}
}
......
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